1.创建复杂对象
复杂对象:类中没有构造方法或者构造方法不能调用,如接口类型或抽象类实例
新建Maven-webapp工程,添加java、resources目录
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>spring03</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>spring03 Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!--spring核心及相关依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.4</version> </dependency> <!--mybatis-spring--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.4</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.19</version> </dependency> </dependencies> <build> <finalName>spring03</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
1.1 抽象类Calendar
CalendarFactoryBean.java
package factorybean; import org.springframework.beans.factory.FactoryBean; import java.util.Calendar; /** * @ClassName CalendarFactoryBean * @Description 用来在工厂中创建复杂对象Calendar * @Author Jiangnan Cui * @Date 2022/4/7 21:33 * @Version 1.0 */ public class CalendarFactoryBean implements FactoryBean<Calendar> { //用来书写复杂对象的创建方式 @Override public Calendar getObject() throws Exception { return Calendar.getInstance(); } //指定创建的复杂对象类型 @Override public Class<?> getObjectType() { return Calendar.class; } //用来指定创建的对象模式 true表示单例,false表示多例 @Override public boolean isSingleton() { return true; } }
spring.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--管理组件对象--> <bean class="factorybean.CalendarFactoryBean" id="calendar"/> </beans>
CalendarTest.java
package test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.Calendar; /** * @ClassName CalendarTest * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/7 21:39 * @Version 1.0 */ public class CalendarTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("factorybean/spring.xml"); Calendar calendar = (Calendar) context.getBean("calendar"); System.out.println(calendar); Calendar calendar1 = (Calendar) context.getBean("calendar"); System.out.println(calendar1); System.out.println(calendar==calendar1); } }
1.2 接口Connection
ConnectionFactoryBean.java
package factorybean; import org.springframework.beans.factory.FactoryBean; import java.sql.Connection; import java.sql.DriverManager; /** * @ClassName ConnectionFactoryBean * @Description 用工厂创建复杂对象Connection * @Author Jiangnan Cui * @Date 2022/4/7 21:43 * @Version 1.0 */ public class ConnectionFactoryBean implements FactoryBean<Connection> { @Override public Connection getObject() throws Exception { Class.forName("com.mysql.jdbc.Driver"); return DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis","root","123456"); } @Override public Class<?> getObjectType() { return Connection.class; } @Override public boolean isSingleton() { return false; } }
spring.xml
<bean class="factorybean.ConnectionFactoryBean" id="connection"/>
ConnectionTest.java
package test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.sql.Connection; /** * @ClassName ConnectionTest * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/7 21:48 * @Version 1.0 */ public class ConnectionTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("factorybean/spring.xml"); Connection connection = (Connection) context.getBean("connection"); System.out.println(connection); Connection connection1 = (Connection) context.getBean("connection"); System.out.println(connection1); System.out.println(connection==connection1); } }
2. SM整合思路
配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili
2.1 spring框架的作用
spring框架 项目管理框架 主要负责项目中组件对象的创建
2.2 Mybatis框架的作用
Mybatis框架 持久层框架 主要用来简化数据库访问的操作
2.3 整合思路
整合思路: 两个框架作用不同,貌似没有什么联系,更深入看才能看出所谓Spring整合Mybatis,其实就是通过spring框架接管mybatis框架中核心对象的创建
2.4 Mybatis中的核心对象
Mybatis的核心对象为: SqlSessionFactory
整合就是通过Spring管理SqlSessionFactory对象的创建
2.5 整合思路
总体示意图:
Spring整合Mybatis思路分析:
Spring整合Mybatis编程步骤:
2.6 具体实现
(1)引入依赖
<!--spring核心及相关依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.4</version> </dependency> <!--mybatis-spring--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.4</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.19</version> </dependency>
(2)配置spring.xml
<!--创建sqlSessionFactory对象--> <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory"> <!--依赖数据源对象--> <property name="dataSource" ref="dataSource"/> <!--依赖mapper文件注册--> </bean> <!--创建数据源对象druid,需要引入druid依赖,类似的数据源还有C3p0、dbcp等--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>
(3)测试SqlSessionFactory是否创建成功
package test; import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @ClassName SqlSessionFactoryTest * @Description 测试SqlSessionFactory是否创建成功 * @Author Jiangnan Cui * @Date 2022/4/8 16:59 * @Version 1.0 */ public class SqlSessionFactoryTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("factorybean/spring.xml"); SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory"); System.out.println(sqlSessionFactory); } }
测试结果:
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@2d2e5f00
3. SM整合DAO编程步骤
配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili
3.0 整合思路
SM整合编码之DAO层思路分析流程:
SM整合之DAO层编程步骤:
3.1 引入mybatis的依赖jar包
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version> </dependency>
3.2 引入Spring相关jar包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency>
3.3 mybatis-spring整合jar
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency>
3.4 引入数据库驱动jar
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.40</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency>
3.5 建表
CREATE TABLE `t_user` ( `id` varchar(40) NOT NULL, `name` varchar(40) DEFAULT NULL, `age` int(3) DEFAULT NULL, `bir` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.6 编写实体类
package entity; import java.util.Date; /** * @ClassName User * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/8 17:44 * @Version 1.0 */ public class User { private String id; private String name; private Integer age; private Date bir; public User() { } public User(String id, String name, Integer age, Date bir) { this.id = id; this.name = name; this.age = age; this.bir = bir; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBir() { return bir; } public void setBir(Date bir) { this.bir = bir; } @Override public String toString() { return "User{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age=" + age + ", bir=" + bir + '}'; } }
3.7 书写DAO接口
package dao; import entity.User; import java.util.List; /** * @ClassName UserDAO * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/8 17:46 * @Version 1.0 */ public interface UserDAO { //根据id查询用户信息 User findById(String id); //查询所有用户信息 List<User> findAll(); //新增用户 void insert(User user); //根据id修改用户 void update(User user); //根据id删除用户 void delete(String id); }
3.8 编写mapper配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <!-- mapper为映射的根节点,用来管理DAO接口 namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名) mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象 --> <mapper namespace="dao.UserDAO"> <!-- id = "接口中的方法名" parameterType = "接口中传入方法的参数类型" resultType = "返回实体类对象:包.类名" 处理结果集 自动封装 注意:sql语句后不要出现";"号 查询:select标签 增加:insert标签 修改:update标签 删除:delete标签 --> <!--根据id查询用户信息--> <select id="findById" parameterType="String" resultType="entity.User"> select id,name,age,bir from t_user where id=#{id} </select> <!--查询所有用户信息--> <select id="findAll" resultType="entity.User"> select id,name,age,bir from t_user </select> <!--新增用户--> <insert id="insert" parameterType="entity.User"> insert into t_user values(#{id},#{name},#{age},#{bir}); </insert> <!--根据id修改用户--> <update id="update" parameterType="entity.User"> update t_user set name=#{name},age=#{age},bir=#{bir} where id=#{id} </update> <!--根据id删除用户--> <delete id="delete" parameterType="String"> delete from t_user where id=#{id} </delete> </mapper>
3.9 编写Spring-myabtis整合配置文件spring.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--创建sqlSessionFactory--> <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory"> <!--依赖数据源--> <property name="dataSource" ref="dataSource"/> <!--注入mapper配置文件--> <property name="mapperLocations"> <array> <!--依次注册mapper--> <value>classpath:mapper/UserDAOMapper.xml</value> </array> </property> </bean> <!--创建dataSource--> <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <!--创建DAO组件类--> <bean class="org.mybatis.spring.mapper.MapperFactoryBean" id="userDAO"> <!--注入SqlSessionFactory--> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> <!--注入创建的DAO接口类型(接口的全限定名:包名.接口名)--> <property name="mapperInterface" value="dao.UserDAO"/> </bean> </beans>
3.10 启动工厂测试
package test; import dao.UserDAO; import entity.User; import org.apache.ibatis.session.SqlSessionFactory; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.web.bind.annotation.RestController; import java.util.Date; import java.util.List; import java.util.UUID; /** * @ClassName UserDAOTest * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/8 17:55 * @Version 1.0 */ public class UserDAOTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); //SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory"); //SqlSession sqlSession = sqlSessionFactory.openSession(); //System.out.println(sqlSession); //UserDAO userDAO = sqlSession.getMapper(UserDAO.class); //mybatis-spring jar MapperFactoryBean 创建DAO对象一个类 // 1.依赖于SqlSessionFactory 2.依赖创建DAO全限定名 UserDAO userDAO = (UserDAO) context.getBean("userDAO"); List<User> users = userDAO.findAll(); users.forEach(user-> System.out.println("user = " + user)); } @Test public void findByIdTest(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserDAO userDAO = (UserDAO) context.getBean("userDAO"); User user1 = userDAO.findById("1"); System.out.println("user1 = " + user1); } @Test public void findAllTest(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserDAO userDAO = (UserDAO) context.getBean("userDAO"); List<User> users = userDAO.findAll(); users.forEach(user -> System.out.println("user = " + user)); } @Test public void insertTest(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserDAO userDAO = (UserDAO) context.getBean("userDAO"); String id = UUID.randomUUID().toString(); userDAO.insert(new User(id,"lisi",60,new Date())); } @Test public void updateTest(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserDAO userDAO = (UserDAO) context.getBean("userDAO"); userDAO.update(new User("4","wangwu",25,new Date())); } @Test public void deleteTest(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserDAO userDAO = (UserDAO) context.getBean("userDAO"); userDAO.delete("4"); } }
补充:SM整合编码之DAO细节优化
即:
(1)mapper配置文件注入方式
a. 以数组形式单个注入
<property name="mapperLocations"> <array> <!--依次注册mapper--> <value>classpath:mapper/UserDAOMapper.xml</value> </array> </property>
b. 通用mapper配置文件扫描注入(推荐使用)
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
+ 补充:起别名
<!-- 注入别名相关配置typeAliasesPackage:用来给指定包中所有类起别名 默认的别名:类名/类名首字母小写 --> <!--指定包--> <property name="typeAliasesPackage" value="entity"/>
(2)创建DAO组件类
a. 单个注入
<bean class="org.mybatis.spring.mapper.MapperFactoryBean" id="userDAO"> <!--注入SqlSessionFactory--> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> <!--注入创建的DAO接口类型(接口的全限定名:包名.接口名)--> <property name="mapperInterface" value="dao.UserDAO"/> </bean>
b. 一次性注入所有(推荐使用)
<!-- 一次项目创建项目中所有DAO对象 MapperScannerConfigurer: 默认创建对象在工厂中的唯一标识为接口首字母小写 例如:UserDAO->userDAO Userdao->userdao OrderDAO->orderDAO Orderdao->orderdao EmpDAO->empDAO --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--注入SqlSessionFactory对象--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> <!--扫描DAO接口所在包--> <property name="basePackage" value="dao"/> </bean>
优化后如下:
<!--创建dataSource--> <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <!--创建sqlSessionFactory--> <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory"> <!--依赖数据源--> <property name="dataSource" ref="dataSource"/> <!--通用mapper配置文件扫描注入,推荐使用--> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <!-- 注入别名相关配置typeAliasesPackage:用来给指定包中所有类起别名 默认的别名:类名/类名首字母小写 --> <!--指定包--> <property name="typeAliasesPackage" value="entity"/> </bean> <!--创建DAO组件类:一次项目创建项目中所有DAO对象--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--注入SqlSessionFactory对象--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> <!--扫描DAO接口所在包--> <property name="basePackage" value="dao"/> </bean>
4. SM整合Service编程步骤
配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili
4.1 整合思路
SM整合之Service层事务控制思路分析:
SM整合DAO和Service部分编程步骤:
具体实现:
4.2 开发Service接口
package service; import entity.User; import java.util.List; /** * @ClassName UserService * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/9 17:13 * @Version 1.0 */ public interface UserService { //查询所有用户 List<User> findAll(); //插入用户数据 void insert(User user); }
4.3 开发Service实现类
package service; import dao.UserDAO; import entity.User; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import java.util.List; import java.util.UUID; /** * @ClassName UserServiceImpl * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/9 17:14 * @Version 1.0 */ public class UserServiceImpl implements UserService{ //Service层需要调用DAO层 private UserDAO userDAO; public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } //生成事务管理器 private PlatformTransactionManager platformTransactionManager; public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) { this.platformTransactionManager = platformTransactionManager; } //查询所有用户信息 //注意:查询不需要事务管理 @Override public List<User> findAll() { return userDAO.findAll(); } //插入用户信息 //注意:增删改需要事务管理 @Override public void insert(User user) { //int i = 1/0; //创建事务配置对象 TransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); //获取事务状态 TransactionStatus status = platformTransactionManager.getTransaction(transactionDefinition); try { //处理业务 user.setId(UUID.randomUUID().toString()); //调用业务 //注意:在DAO层进行数据库增删改时,也能操作成功的原因是因为DAO层提供了方法测试的小事务,方便测试DAO // 当外部存在事务时,小事务自动消失 userDAO.insert(user); platformTransactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); platformTransactionManager.rollback(status); } } }
4.4 编写spring.xml
<!--配置数据源事务管理器--> <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"> <!--注入数据源对象 DataSource--> <property name="dataSource" ref="dataSource"/> </bean> <!--管理Service组件--> <bean class="service.UserServiceImpl" id="userService"> <!--Service组件需要DAO组件,需要注入--> <property name="userDAO" ref="userDAO"/> <!--需要在Service进行事务管理--> <property name="platformTransactionManager" ref="transactionManager"/> </bean>
4.5 启动工厂测试
package test; import entity.User; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import service.UserService; import java.util.Date; /** * @ClassName UserServiceTest * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/9 17:41 * @Version 1.0 */ public class UserServiceTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = (UserService) context.getBean("userService"); //System.out.println(userService.getClass()); userService.insert(new User(null,"小超超",36,new Date())); userService.findAll().forEach(user -> System.out.println("user = " + user)); } }
4.6 小结
配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili
5. SM整合Service层事务优化思路分析
配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili
spring中的两种事务管理方式:
spring中声明式事务分析思路:
具体实现如下:
5.1 在spring-mybatis.xml文件中添加配置
<!--管理Service组件--> <bean class="service.UserServiceImpl" id="userService"> <!--Service组件需要DAO组件,需要注入--> <property name="userDAO" ref="userDAO"/> <!--Service组件原有的事务管理移出--> </bean> <!--创建数据源事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源对象 DataSource--> <property name="dataSource" ref="dataSource"/> </bean> <!--配置事务属性 tx:advice标签 id: 基于事务管理器创建的环绕通知对象在工厂中唯一标识 作用: 1.根据指定的事务管理器在工厂中创建一个事务的环绕通知对象 2.对业务层方法进行细粒度事务控制 transactionManager:指定事务管理器是谁 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--事务细粒度配置--> <tx:attributes> <!--*表示任意,此处针对增删改方法添加事务管理--> <tx:method name="insert*"/> <tx:method name="delete*"/> <tx:method name="update*"/> </tx:attributes> </tx:advice> <!--配置事务切面--> <aop:config> <!--指定切点--> <aop:pointcut id="pc" expression="within(service.*ServiceImpl)"/> <!--绑定切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/> </aop:config>
5.2 配置图示
5.3 优化UserServiceImpl实现类
package service; import dao.UserDAO; import entity.User; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import java.util.List; import java.util.UUID; /** * @ClassName UserServiceImpl * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/9 17:14 * @Version 1.0 */ public class UserServiceImpl implements UserService{ //Service层需要调用DAO层 private UserDAO userDAO; public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } /** * @MethodName findAll * @Description 查询所有用户信息,查询不需要事务管理 * @return: java.util.List<entity.User> * @Author Jiangnan Cui * @Date 2022/4/11 21:31 */ @Override public List<User> findAll() { return userDAO.findAll(); } /** * @MethodName insert * @Description 插入用户信息,需要事务管理 * @param: user * @Author Jiangnan Cui * @Date 2022/4/11 21:29 */ @Override public void insert(User user) { //处理业务 user.setId(UUID.randomUUID().toString()); //调用业务 //注意:在DAO层进行数据库增删改时,也能操作成功的原因是因为DAO层提供了方法测试的小事务,方便测试DAO // 当外部存在事务时,小事务自动消失 userDAO.insert(user); //int i = 1/0;//测试异常 } }
5.4 启动测试
package test; import entity.User; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import service.UserService; import java.util.Date; /** * @ClassName UserServiceTest * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/9 17:41 * @Version 1.0 */ public class UserServiceTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = (UserService) context.getBean("userService"); //System.out.println(userService.getClass()); //insert userService.insert(new User(null,"小胖墩",3,new Date())); //findAll userService.findAll().forEach(user -> System.out.println("user = " + user)); } }
测试结果:
(1)不注释int i = 1/0;数据插入不成功
Exception in thread "main" java.lang.ArithmeticException: / by zero at service.UserServiceImpl.insert(UserServiceImpl.java:63) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy9.insert(Unknown Source) at test.UserServiceTest.main(UserServiceTest.java:23)
(2)注释掉int i = 1/0;数据插入成功
user = User{id='1', name='张三', age=10, bir=Fri Apr 01 00:00:00 CST 2022} user = User{id='2', name='李四', age=20, bir=Sat Apr 02 00:00:00 CST 2022} user = User{id='2f278828-6422-432d-ab1b-a727b33c23bc', name='小胖墩', age=3, bir=Mon Apr 11 21:43:57 CST 2022} user = User{id='3', name='王五', age=30, bir=Sun Apr 03 00:00:00 CST 2022} user = User{id='4', name='灰太狼', age=60, bir=Sun Apr 10 09:56:17 CST 2022} user = User{id='5', name='小超超', age=36, bir=Sun Apr 10 09:55:41 CST 2022} user = User{id='6', name='小呆呆', age=60, bir=Sun Apr 10 09:55:43 CST 2022} user = User{id='7', name='小超超', age=36, bir=Sun Apr 10 09:55:44 CST 2022} user = User{id='8', name='胖嘟嘟', age=50, bir=Sun Apr 10 09:55:39 CST 2022} user = User{id='9', name='小崔', age=25, bir=Sun Apr 10 09:55:52 CST 2022} user = User{id='e3863fd3-173c-46f4-a753-c72f7c92ad56', name='小猫咪', age=3, bir=Mon Apr 11 21:36:31 CST 2022}
5.5 SM最终开发步骤
配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili
5.6 SM中添加log4j日志
配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili
pom.xml中添加依赖:
<!--log4j依赖--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency> </dependencies>
在src-main-resources下新建log4j.properties:
## 根日志 ## 日志级别 log4j.rootLogger=ERROR,stdout ## 输出位置 log4j.appender.stdout=org.apache.log4j.ConsoleAppender ## 布局 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout ## 格式 log4j.appender.stdout.layout.conversionPattern=[%p] %d{yyyy-MM-dd} %m%n ## 子日志 ## 日志级别 log4j.logger.dao=DEBUG ## 监听spring框架的日志级别 log4j.logger.org.springframework=ERROR
测试结果:
[DEBUG] 2022-04-12 ==> Preparing: insert into t_user values(?,?,?,?); [DEBUG] 2022-04-12 ==> Parameters: 8a3e8ab8-5abc-44e1-9aec-31f3978d97f2(String), 小胖墩(String), 3(Integer), 2022-04-12 10:23:32.991(Timestamp) [DEBUG] 2022-04-12 <== Updates: 1 [DEBUG] 2022-04-12 ==> Preparing: select id,name,age,bir from t_user [DEBUG] 2022-04-12 ==> Parameters: [DEBUG] 2022-04-12 <== Total: 14 user = User{id='1', name='张三', age=10, bir=Fri Apr 01 00:00:00 CST 2022} user = User{id='2', name='李四', age=20, bir=Sat Apr 02 00:00:00 CST 2022} user = User{id='2f278828-6422-432d-ab1b-a727b33c23bc', name='小胖墩', age=3, bir=Mon Apr 11 21:43:57 CST 2022} user = User{id='3', name='王五', age=30, bir=Sun Apr 03 00:00:00 CST 2022} user = User{id='4', name='灰太狼', age=60, bir=Sun Apr 10 09:56:17 CST 2022} user = User{id='5', name='小超超', age=36, bir=Sun Apr 10 09:55:41 CST 2022} user = User{id='586a5f71-836c-4171-a038-4620fe0f9354', name='葫芦娃', age=5, bir=Tue Apr 12 09:45:17 CST 2022} user = User{id='6', name='小呆呆', age=60, bir=Sun Apr 10 09:55:43 CST 2022} user = User{id='7', name='小超超', age=36, bir=Sun Apr 10 09:55:44 CST 2022} user = User{id='8', name='胖嘟嘟', age=50, bir=Sun Apr 10 09:55:39 CST 2022} user = User{id='8a3e8ab8-5abc-44e1-9aec-31f3978d97f2', name='小胖墩', age=3, bir=Tue Apr 12 10:23:33 CST 2022} user = User{id='9', name='小崔', age=25, bir=Sun Apr 10 09:55:52 CST 2022} user = User{id='cd280176-68b2-4ceb-b781-ba2f5e1fbeff', name='小胖墩', age=3, bir=Tue Apr 12 10:21:18 CST 2022} user = User{id='e3863fd3-173c-46f4-a753-c72f7c92ad56', name='小猫咪', age=3, bir=Mon Apr 11 21:36:31 CST 2022}
注:ERROR前还有OFF,一般不用。