Required reading: learning suggestions
This tutorial is hand-in-hand teaching and introduces how to integrate MyBatis through the Spring framework. Follow the tutorial steps to complete the integration of MyBatis and Spring framework. Try it quickly! The configuration process must be careful~~
Knowledge expansion: comparison of various database connection pools: Comparison of c3p0, DBCP and Druid connection pools_ Blog of wawa3338 - CSDN blog_ dbcp druid
1, Spring integration MyBatis steps
The first step is to introduce dependent packages
The jar packages that the project depends on are as follows:
Maven: aopalliance:aopalliance:1.0
Maven: com.google.protobuf:protobuf-java:3.6.1
Maven: commons-dbcp:commons-dbcp:1.4
Maven: commons-pool:commons-pool:1.6
Maven: junit:junit:4.13
Maven: log4j:log4j:1.2.17
Maven: mysql:mysql-connector-java:8.0.18
Maven: org.aspectj:aspectjweaver:1.9.6
Maven: org.hamcrest:hamcrest:2.2
Maven: org.hamcrest:hamcrest-core:2.2
Maven: org.mybatis:mybatis:3.5.6
Maven: org.mybatis:mybatis-spring:2.0.6
Maven: org.springframework:spring-aop:5.3.4
Maven: org.springframework:spring-beans:5.3.4
Maven: org.springframework:spring-context:5.3.4
Maven: org.springframework:spring-core:5.3.4
Maven: org.springframework:spring-expression:5.3.4
Maven: org.springframework:spring-jcl:5.3.4
Maven: org.springframework:spring-jdbc:5.3.4
Maven: org.springframework:spring-tx:5.3.4
Note: to create a project using maven, all the dependent packages required are as follows. Maven: org. MyBatis: MyBatis Spring: 2.0.6 is a dependency package integrated by MyBatis using the Spring framework.
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>com.bdqn</groupId> <artifactId>s3-spring-mybatis</artifactId> <version>1.0-SNAPSHOT</version> <name>s3-spring-mybatis</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.4</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> <version>2.2</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.18</version> </dependency> <!-- Spring integration MyBatis Required package --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.3.4</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.6</version> </dependency> </dependencies> <!-- Configure resource directory --> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> </resources> </build> </project>
The second step is to write entity classes and three-tier patterns
Entity class SysUser.java
package com.bdqn.pojo; import java.util.Date; /** * System user entity * * @author Miku * @since 2021-05-14 */ public class SysUser { private Integer id; //id private String account; //User code private String realName; //User name private String password; //User password private Integer sex; //Gender private Date birthday; //date of birth private String phone; //Telephone private String address; //address private Integer roleId; //User role ID private Integer createdUserId; //creator private Date createdTime; //Creation time private Integer updatedUserId; //Updater private Date updatedTime; //Update time private Integer age;//Age private String roleIdName; //User role name public Integer getAge() { /*long time = System.currentTimeMillis()-birthday.getTime(); Integer age = Long.valueOf(time/365/24/60/60/1000).IntegerValue();*/ Date date = new Date(); Integer age = date.getYear() - birthday.getYear(); return age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getRealName() { return realName; } public void setRealName(String realName) { this.realName = realName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Integer getRoleId() { return roleId; } public void setRoleId(Integer roleId) { this.roleId = roleId; } public Integer getCreatedUserId() { return createdUserId; } public void setCreatedUserId(Integer createdUserId) { this.createdUserId = createdUserId; } public Date getCreatedTime() { return createdTime; } public void setCreatedTime(Date createdTime) { this.createdTime = createdTime; } public Integer getUpdatedUserId() { return updatedUserId; } public void setUpdatedUserId(Integer updatedUserId) { this.updatedUserId = updatedUserId; } public Date getUpdatedTime() { return updatedTime; } public void setUpdatedTime(Date updatedTime) { this.updatedTime = updatedTime; } public void setAge(Integer age) { this.age = age; } public String getRoleIdName() { return roleIdName; } public void setRoleIdName(String roleIdName) { this.roleIdName = roleIdName; } @Override public String toString() { return "SysUser{" + "id=" + id + ", account='" + account + '\'' + ", realName='" + realName + '\'' + ", password='" + password + '\'' + ", sex=" + sex + ", birthday=" + birthday + ", phone='" + phone + '\'' + ", address='" + address + '\'' + ", roleId=" + roleId + ", createdUserId=" + createdUserId + ", createdTime=" + createdTime + ", updatedUserId=" + updatedUserId + ", updatedTime=" + updatedTime + ", age=" + age + ", roleIdName='" + roleIdName + '\'' + '}'; } }
Database DAO interface SysUserMapper.java
package com.bdqn.dao; import com.bdqn.pojo.SysUser; import java.util.List; /** * SysUserMapper Data access layer interface * * @author Miku * @since 2021-05-14 */ public interface SysUserMapper { /** * Query user list * * @param sysUser * @return */ public List<SysUser> selectSysUserList(SysUser sysUser); }
MyBatis mapping file SysUserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SysUserMapper Interface MyBatis Mapping file --> <mapper namespace="com.bdqn.dao.SysUserMapper"> <!-- When the field information in the database is inconsistent with the attributes of the object, you need to pass the resultMap To map --> <resultMap id="SysUserResult" type="SysUser"> <result property="roleIdName" column="roleName"/> </resultMap> <!-- Query user list-roleId by null 0 pieces of data were found during query --> <select id="selectSysUserList" parameterType="SysUser" resultMap="SysUserResult"> select u.*, r.roleName from t_sys_user u, t_sys_role r where u.roleId = r.id and u.roleId = #{roleId} and u.realName like CONCAT('%', #{realName}, '%') </select> </mapper>
Database interface implementation class SysUserMapperImpl.java
package com.bdqn.dao; import com.bdqn.pojo.SysUser; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; /** * SysUserMapper Implementation class (operate the database through SqlSessionTemplate) * * @author Miku * @since 2021-05-14 */ public class SysUserMapperImpl implements SysUserMapper { // The class provided in the mybatis spring package that implements the SqlSession interface is used to operate the database private SqlSessionTemplate sqlSession; /** * Query user list * * @param sysUser * @return */ @Override public List<SysUser> selectSysUserList(SysUser sysUser) { return sqlSession.getMapper(SysUserMapper.class).selectSysUserList(sysUser); } public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } }
Service layer interface SysUserService.java
package com.bdqn.service; import com.bdqn.pojo.SysUser; import java.util.List; /** * SysUserService Service layer interface * * @author Miku * @since 2021-05-14 */ public interface SysUserService { /** * Get user list * * @param sysUser * @return */ public List<SysUser> getList(SysUser sysUser); }
Service layer interface implementation class SysUserServiceImpl.java
package com.bdqn.service; import com.bdqn.dao.SysUserMapper; import com.bdqn.pojo.SysUser; import java.util.List; /** * SysUserService Service layer implementation class * * @author Miku * @since 2021-05-14 */ public class SysUserServiceImpl implements SysUserService { private SysUserMapper sysUserMapper; @Override public List<SysUser> getList(SysUser sysUser) { try { return sysUserMapper.selectSysUserList(sysUser); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } public void setSysUserMapper(SysUserMapper sysUserMapper) { this.sysUserMapper = sysUserMapper; } }
Step 3: configure the MyBatis core configuration file
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- Type alias, configure the basic package, and then Mapper.xml The class name can be abbreviated in lowercase in the file --> <typeAliases> <package name="com.bdqn.pojo" /> </typeAliases> </configuration>
Note: leave the configuration of the data source to Spring. According to the above configuration, comment out the introduction of external data source configuration and MyBatis data source environment configuration.
Step 4 configure the Spring core configuration file
unit testing
applicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- Configure database connection pool --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/cvs_db?serverTimezone=UTC&characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="lilibo"/> </bean> <!-- to configure SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- Reference database configuration<bean id="dataSource"> --> <property name="dataSource" ref="dataSource"/> <!-- introduce MyBatis configuration file --> <property name="configLocation" value="classpath:mybatis-config.xml" /> <!--to configure SQL Map file information--> <property name="mapperLocations"> <list> <value>classpath:com/bdqn/dao/**/*.xml</value> </list> </property> </bean> <!-- to configure SqlSessionTemplate --> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <!--take sqlSessionFactory Inject into sqlSessionTemplate Medium( ref="sqlSessionFactory" ==> <bean id="sqlSessionFactory">)--> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> <!-- to configure DAO --> <bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperImpl"> <property name="sqlSession" ref="sqlSessionTemplate" /> </bean> <!-- to configure Service --> <bean id="sysUserService" class="com.bdqn.service.SysUserServiceImpl"> <property name="sysUserMapper" ref="sysUserMapper" /> </bean> </beans>
unit testing
Create SysUserTest.java under the project test
package com.bdqn; import com.bdqn.pojo.SysUser; import com.bdqn.service.SysUserService; import org.apache.log4j.Logger; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.ArrayList; import java.util.List; /** * SysUser Business test * * @author Miku * @since 2021-05-14 */ public class SysUserTest { private Logger logger = Logger.getLogger(SysUserTest.class); @Before public void setUp() throws Exception { } @Test public void testGetUserList() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); SysUserService userService = (SysUserService) ctx.getBean("sysUserService"); List<SysUser> userList = new ArrayList<SysUser>(); SysUser sysUser = new SysUser(); sysUser.setRealName("Zhao"); sysUser.setRoleId(2); userList = userService.getList(sysUser); for (SysUser userResult : userList) { logger.debug("testGetUserList account: " + userResult.getAccount() + " and realName: " + userResult.getRealName() + " and roleId: " + userResult.getRoleId() + " and roleName: " + userResult.getRoleIdName() + " and address: " + userResult.getAddress()); } } }
[test results]
C:\Java\jdk1.8.0_261\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\lib\idea_rt.jar=58319:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\plugins\junit\lib\junit-rt.jar;C:\Java\jdk1.8.0_261\jre\lib\charsets.jar;C:\Java\jdk1.8.0_261\jre\lib\deploy.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\access-bridge-64.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\cldrdata.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\dnsns.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\jaccess.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\jfxrt.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\localedata.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\nashorn.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunec.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunjce_provider.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunmscapi.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunpkcs11.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\zipfs.jar;C:\Java\jdk1.8.0_261\jre\lib\javaws.jar;C:\Java\jdk1.8.0_261\jre\lib\jce.jar;C:\Java\jdk1.8.0_261\jre\lib\jfr.jar;C:\Java\jdk1.8.0_261\jre\lib\jfxswt.jar;C:\Java\jdk1.8.0_261\jre\lib\jsse.jar;C:\Java\jdk1.8.0_261\jre\lib\management-agent.jar;C:\Java\jdk1.8.0_261\jre\lib\plugin.jar;C:\Java\jdk1.8.0_261\jre\lib\resources.jar;C:\Java\jdk1.8.0_261\jre\lib\rt.jar;D:\Works\ktjiaoyu\s3-spring-mybatis\target\test-classes;D:\Works\ktjiaoyu\s3-spring-mybatis\target\classes;D:\Source\maven\repository\junit\junit\4.13\junit-4.13.jar;D:\Source\maven\repository\org\springframework\spring-aop\5.3.4\spring-aop-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-beans\5.3.4\spring-beans-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-context\5.3.4\spring-context-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-core\5.3.4\spring-core-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-jcl\5.3.4\spring-jcl-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-expression\5.3.4\spring-expression-5.3.4.jar;D:\Source\maven\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;D:\Source\maven\repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;D:\Source\maven\repository\org\hamcrest\hamcrest-core\2.2\hamcrest-core-2.2.jar;D:\Source\maven\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;D:\Source\maven\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;D:\Source\maven\repository\org\mybatis\mybatis\3.5.6\mybatis-3.5.6.jar;D:\Source\maven\repository\mysql\mysql-connector-java\8.0.18\mysql-connector-java-8.0.18.jar;D:\Source\maven\repository\com\google\protobuf\protobuf-java\3.6.1\protobuf-java-3.6.1.jar;D:\Source\maven\repository\org\mybatis\mybatis-spring\2.0.6\mybatis-spring-2.0.6.jar;D:\Source\maven\repository\org\springframework\spring-jdbc\5.3.4\spring-jdbc-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-tx\5.3.4\spring-tx-5.3.4.jar;D:\Source\maven\repository\commons-dbcp\commons-dbcp\1.4\commons-dbcp-1.4.jar;D:\Source\maven\repository\commons-pool\commons-pool\1.6\commons-pool-1.6.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.bdqn.SysUserTest,testGetUserList [DEBUG] 2021-05-17 01:14:18,457 com.bdqn.SysUserTest - testGetUserList account: zhaogang and realName: Zhao Gang and roleId: 2 and roleName: shopowner and address: Guanzhuang crescent community, Fengtai District, Beijing Process finished with exit code 0
So far, Spring has integrated MyBatis configuration.
Optimization 1: replace SqlSessionTemplate with SqlSessionDaoSupport
In addition to directly using SqlSessionTempIate to obtain the SqlSession instance processing data, mybatis spring also provides the SqlSessionDaoSupport class to simplify the SqlSessionTemplate. Obtain the SqlSession object through this.getSqlSession() to perform database operations.
Create SysUserMapperDaoSupportImpl.java under com.bdqn.dao package
package com.bdqn.dao; import com.bdqn.pojo.SysUser; import org.mybatis.spring.support.SqlSessionDaoSupport; import java.util.List; /** * Inherit the implementation of SqlSessionDaoSupport abstract class (obtain the SqlSession object through getSqlSession() method and operate the database) * * @author Miku * @since 2021-05-14 */ public class SysUserMapperDaoSupportImpl extends SqlSessionDaoSupport implements SysUserMapper { /** * Query user list * * @param sysUser * @return */ @Override public List<SysUser> selectSysUserList(SysUser sysUser) { return this.getSqlSession().getMapper(SysUserMapper.class).selectSysUserList(sysUser); } }
Note: after inheriting SqlSessionDaoSupport, you do not need to define the attribute SqlSession. SqlSession directly obtains the SqlSession object through this.getSqlSession() to perform database operations.
Modify the corresponding configuration of applicationContext.xml
<!-- to configure DAO 1, Use SqlSessionTemplate edition --> <!-- MyBatis-Spring Provided SqlSessionTemplate Class, inherited SqlSession Interface, operating database --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperImpl"> <property name="sqlSession" ref="sqlSessionTemplate" /> </bean>--> <!-- to configure DAO 2, Use SqlSessionDaoSupport edition --> <!-- MyBatis-Spring Provided through this.getSqlSession()Method obtain SqlSession The instance operates the database and does not need to be defined SqlSession Object, which is more convenient to use --> <bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperDaoSupportImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
Note: note that the first method is the SqlSessionTemplate version. Replace it with the second method and use the SqlSessionDaoSupport version.
Optimization II using MapperFactoryBean injection mapper
The MapperFactoryBean provided by mybatis spring can generate the implementation class of the mapper in the way of configuration and inject it into the business component without writing the DAO implementation class.
Modify the corresponding configuration of applicationContext.xml
<!-- to configure SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- Reference database configuration<bean id="dataSource"> --> <property name="dataSource" ref="dataSource"/> <!-- introduce MyBatis configuration file --> <property name="configLocation" value="classpath:mybatis-config.xml" /> <!-- to configure SQL Map file information --> <!-- use MyBatis-Spring Provided MapperFactoryBean If the mapper corresponds to SQL The mapping file is the same as the class path of the mapper and can be automatically mapped MapperFactoryBean Resolve. In this case, configure SessionFactoryBean You don't have to specify SQL The location of the mapping file. Conversely, if the class path of the mapper is different from that of the mapping file, you still need to specify the location of the mapping file explicitly --> <!--<property name="mapperLocations"> <list> <value>classpath:com/bdqn/dao/**/*.xml</value> </list> </property>--> </bean> <!-- to configure DAO 1, Use SqlSessionTemplate edition --> <!-- MyBatis-Spring Provided SqlSessionTemplate Class, inherited SqlSession Interface, operating database --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperImpl"> <property name="sqlSession" ref="sqlSessionTemplate" /> </bean>--> <!-- to configure DAO 2, Use SqlSessionDaoSupport edition --> <!-- MyBatis-Spring Provided through this.getSqlSession()Method obtain SqlSession The instance operates the database and does not need to be defined SqlSession Object, which is more convenient to use --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperDaoSupportImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>--> <!-- to configure DAO 3, Use MapperFactoryBean edition --> <!-- MyBatis-Spring Provided MapperFactoryBean It can generate the implementation class of the mapper in the way of configuration and inject it into the business component without writing DAO Implementation class --> <bean id="sysUserMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <property name="mapperInterface" value="com.bdqn.dao.SysUserMapper" /> </bean>
Note: after configuration by using MapperFactoryBean (the third method), you do not need to write the implementation class of DAO, but only the mapping file of Mapper.xml.
Optimization 3: using mappercannerconfig to inject mapper
Configuring MapperFactoryBean for mappers greatly simplifies the coding of DAO modules. However, if there are many mappers, there will be many corresponding configuration items. In order to simplify the configuration workload, mybatis spring provides mappercannerconfigurer, which can scan the interfaces in the specified package and directly register them as MapperFactoryBean.
Modify the corresponding configuration of applicationContext.xml
<!-- to configure DAO 1, Use SqlSessionTemplate edition --> <!-- MyBatis-Spring Provided SqlSessionTemplate Class, inherited SqlSession Interface, operating database --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperImpl"> <property name="sqlSession" ref="sqlSessionTemplate" /> </bean>--> <!-- to configure DAO 2, Use SqlSessionDaoSupport edition --> <!-- MyBatis-Spring Provided through this.getSqlSession()Method obtain SqlSession The instance operates the database and does not need to be defined SqlSession Object, which is more convenient to use --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperDaoSupportImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>--> <!-- to configure DAO 3, Use MapperFactoryBean edition --> <!-- MyBatis-Spring Provided MapperFactoryBean It can generate the implementation class of the mapper in the way of configuration and inject it into the business component without writing DAO Implementation class --> <!--<bean id="sysUserMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <property name="mapperInterface" value="com.bdqn.dao.SysUserMapper" /> </bean>--> <!-- to configure DAO 4, Use MapperScannerConfig edition --> <!-- MyBatis-Spring Provided MapperScannerConfigurer All interfaces under the benchmark package (including sub packages at all levels) will be recursively scanned. If they are in SQL If they are defined in the mapping file, they will be dynamically registered as the implementation class of the mapper, and the implementation class of the mapper can be generated in batch --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.bdqn.dao" /> </bean>
Note: after configuration by using mappercannerconfigurer (the fourth method), the specified basePackage package is called the benchmark package, and mappercannerconfigurer will recursively scan all interfaces under the benchmark package (including sub packages at all levels). If they have been defined in the SQL mapping file, they will be dynamically registered as mapper implementation classes to generate mapper implementation classes in batch.
Full applicationContext.xml configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- Configure database connection pool --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/cvs_db?serverTimezone=UTC&characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="lilibo"/> </bean> <!-- to configure SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- Reference database configuration<bean id="dataSource"> --> <property name="dataSource" ref="dataSource"/> <!-- introduce MyBatis configuration file --> <property name="configLocation" value="classpath:mybatis-config.xml" /> <!-- to configure SQL Map file information --> <!-- use MyBatis-Spring Provided MapperFactoryBean If the mapper corresponds to SQL The mapping file is the same as the class path of the mapper and can be automatically mapped MapperFactoryBean Analysis. In this case, configure SessionFactoryBean You don't have to specify SQL The location of the mapping file. Conversely, if the class path of the mapper is different from that of the mapping file, you still need to specify the location of the mapping file --> <!--<property name="mapperLocations"> <list> <value>classpath:com/bdqn/dao/**/*.xml</value> </list> </property>--> </bean> <!-- to configure SqlSessionTemplate --> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <!-- take sqlSessionFactory Inject into sqlSessionTemplate Medium( ref="sqlSessionFactory" ==> <bean id="sqlSessionFactory">) --> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> <!-- to configure DAO 1, Use SqlSessionTemplate edition --> <!-- MyBatis-Spring Provided SqlSessionTemplate Class, inherited SqlSession Interface, operating database --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperImpl"> <property name="sqlSession" ref="sqlSessionTemplate" /> </bean>--> <!-- to configure DAO 2, Use SqlSessionDaoSupport edition --> <!-- MyBatis-Spring Provided through this.getSqlSession()Method obtain SqlSession The instance operates the database and does not need to be defined SqlSession Object, which is more convenient to use --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperDaoSupportImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>--> <!-- to configure DAO 3, Use MapperFactoryBean edition --> <!-- MyBatis-Spring Provided MapperFactoryBean It can generate the implementation class of the mapper in the way of configuration and inject it into the business component without writing DAO Implementation class --> <!--<bean id="sysUserMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <property name="mapperInterface" value="com.bdqn.dao.SysUserMapper" /> </bean>--> <!-- to configure DAO 4, Use MapperScannerConfig edition --> <!-- MyBatis-Spring Provided MapperScannerConfigurer All interfaces under the benchmark package (including sub packages at all levels) will be recursively scanned. If they are in SQL If they are defined in the mapping file, they will be dynamically registered as the implementation class of the mapper, and the implementation class of the mapper can be generated in batch --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.bdqn.dao" /> </bean> <!-- to configure Service --> <bean id="sysUserService" class="com.bdqn.service.SysUserServiceImpl"> <property name="sysUserMapper" ref="sysUserMapper" /> </bean> </beans>
Annotation method uses annotations to simplify business layer configuration
When a mapper is registered to the Spring container, the Spring framework will name it according to its interface name, which is a lowercase, non fully qualified name by default. For example, a component of type sysusermapper is named sysusermapper by default. During development, you can use @ Autowired or @ Resource annotations to implement dependency injection on business components to simplify the configuration of business components
Modify the SysUserServiceImpl.java file with annotations
package com.bdqn.service; import com.bdqn.dao.SysUserMapper; import com.bdqn.pojo.SysUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * SysUserService Service layer implementation class * * @author Miku * @since 2021-05-14 */ @Service("sysUserService") // Bean registered as a Service layer public class SysUserServiceImpl implements SysUserService { @Autowired // @Resource / / inject beans of DAO layer by annotation private SysUserMapper sysUserMapper; @Override public List<SysUser> getList(SysUser sysUser) { try { return sysUserMapper.selectSysUserList(sysUser); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } }
Summary:
Annotations for Spring registered beans include
- @Component: used to label the class as a Bean
- @Repository: used to label DAO class as a Bean
- @Service: used to mark the business class as a Bean
- @Controller: used to label the controller class as a Bean
Note: for annotation configuration, you need to modify the Spring configuration file, remove the configuration of business layer beans, and add the business beans defined by scanning annotations
Modify applicationContext.xml configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- Configure database connection pool --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/cvs_db?serverTimezone=UTC&characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="lilibo"/> </bean> <!-- to configure SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- Reference database configuration<bean id="dataSource"> --> <property name="dataSource" ref="dataSource"/> <!-- introduce MyBatis configuration file --> <property name="configLocation" value="classpath:mybatis-config.xml" /> <!-- to configure SQL Map file information --> <!-- use MyBatis-Spring Provided MapperFactoryBean If the mapper corresponds to SQL The mapping file is the same as the class path of the mapper and can be automatically mapped MapperFactoryBean Resolve. In this case, configure SessionFactoryBean You don't have to specify SQL The location of the mapping file. Conversely, if the class path of the mapper is different from that of the mapping file, you still need to specify the location of the mapping file explicitly --> <!--<property name="mapperLocations"> <list> <value>classpath:com/bdqn/dao/**/*.xml</value> </list> </property>--> </bean> <!-- to configure SqlSessionTemplate --> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <!-- take sqlSessionFactory Inject into sqlSessionTemplate Medium( ref="sqlSessionFactory" ==> <bean id="sqlSessionFactory">) --> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> <!-- to configure DAO 1, Use SqlSessionTemplate edition --> <!-- MyBatis-Spring Provided SqlSessionTemplate Class, inherited SqlSession Interface, operating database --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperImpl"> <property name="sqlSession" ref="sqlSessionTemplate" /> </bean>--> <!-- to configure DAO 2, Use SqlSessionDaoSupport edition --> <!-- MyBatis-Spring Provided through this.getSqlSession()Method obtain SqlSession The instance operates the database and does not need to be defined SqlSession Object, which is more convenient to use --> <!--<bean id="sysUserMapper" class="com.bdqn.dao.SysUserMapperDaoSupportImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>--> <!-- to configure DAO 3, Use MapperFactoryBean edition --> <!-- MyBatis-Spring Provided MapperFactoryBean It can generate the implementation class of the mapper in the way of configuration and inject it into the business component without writing DAO Implementation class --> <!--<bean id="sysUserMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <property name="mapperInterface" value="com.bdqn.dao.SysUserMapper" /> </bean>--> <!-- to configure DAO 4, Use MapperScannerConfig edition --> <!-- MyBatis-Spring Provided MapperScannerConfigurer All interfaces under the benchmark package (including sub packages at all levels) will be recursively scanned. If they are in SQL If they are defined in the mapping file, they will be dynamically registered as the implementation class of the mapper, and the implementation class of the mapper can be generated in batch --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.bdqn.dao" /> </bean> <!-- to configure Service --> <!-- Use annotation to configure business Bean Delete the configuration when --> <!--<bean id="sysUserService" class="com.bdqn.service.SysUserServiceImpl"> <property name="sysUserMapper" ref="sysUserMapper" /> </bean>--> <!-- Configure by annotation and define the scanned package --> <context:component-scan base-package="com.bdqn.service" /> </beans>
Rerun the unit tests after each configuration optimization
[test results]
C:\Java\jdk1.8.0_261\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\lib\idea_rt.jar=58319:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.3\plugins\junit\lib\junit-rt.jar;C:\Java\jdk1.8.0_261\jre\lib\charsets.jar;C:\Java\jdk1.8.0_261\jre\lib\deploy.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\access-bridge-64.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\cldrdata.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\dnsns.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\jaccess.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\jfxrt.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\localedata.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\nashorn.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunec.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunjce_provider.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunmscapi.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\sunpkcs11.jar;C:\Java\jdk1.8.0_261\jre\lib\ext\zipfs.jar;C:\Java\jdk1.8.0_261\jre\lib\javaws.jar;C:\Java\jdk1.8.0_261\jre\lib\jce.jar;C:\Java\jdk1.8.0_261\jre\lib\jfr.jar;C:\Java\jdk1.8.0_261\jre\lib\jfxswt.jar;C:\Java\jdk1.8.0_261\jre\lib\jsse.jar;C:\Java\jdk1.8.0_261\jre\lib\management-agent.jar;C:\Java\jdk1.8.0_261\jre\lib\plugin.jar;C:\Java\jdk1.8.0_261\jre\lib\resources.jar;C:\Java\jdk1.8.0_261\jre\lib\rt.jar;D:\Works\ktjiaoyu\s3-spring-mybatis\target\test-classes;D:\Works\ktjiaoyu\s3-spring-mybatis\target\classes;D:\Source\maven\repository\junit\junit\4.13\junit-4.13.jar;D:\Source\maven\repository\org\springframework\spring-aop\5.3.4\spring-aop-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-beans\5.3.4\spring-beans-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-context\5.3.4\spring-context-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-core\5.3.4\spring-core-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-jcl\5.3.4\spring-jcl-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-expression\5.3.4\spring-expression-5.3.4.jar;D:\Source\maven\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;D:\Source\maven\repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;D:\Source\maven\repository\org\hamcrest\hamcrest-core\2.2\hamcrest-core-2.2.jar;D:\Source\maven\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;D:\Source\maven\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;D:\Source\maven\repository\org\mybatis\mybatis\3.5.6\mybatis-3.5.6.jar;D:\Source\maven\repository\mysql\mysql-connector-java\8.0.18\mysql-connector-java-8.0.18.jar;D:\Source\maven\repository\com\google\protobuf\protobuf-java\3.6.1\protobuf-java-3.6.1.jar;D:\Source\maven\repository\org\mybatis\mybatis-spring\2.0.6\mybatis-spring-2.0.6.jar;D:\Source\maven\repository\org\springframework\spring-jdbc\5.3.4\spring-jdbc-5.3.4.jar;D:\Source\maven\repository\org\springframework\spring-tx\5.3.4\spring-tx-5.3.4.jar;D:\Source\maven\repository\commons-dbcp\commons-dbcp\1.4\commons-dbcp-1.4.jar;D:\Source\maven\repository\commons-pool\commons-pool\1.6\commons-pool-1.6.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.bdqn.SysUserTest,testGetUserList [DEBUG] 2021-05-17 01:14:18,457 com.bdqn.SysUserTest - testGetUserList account: zhaogang and realName: Zhao Gang and roleId: 2 and roleName: shopowner and address: Guanzhuang crescent community, Fengtai District, Beijing Process finished with exit code 0
Spring integration MyBatis configuration summary
- SqlSessionTemplate mybatis spring provides the SqlSessionTemplate class, inherits the SqlSession interface, and operates the database
- Sqlsessiondaosupport mybatis spring provides SqlSession instance operation database through this.getSqlSession() method, which is more convenient to use without defining SqlSession object
- MapperFactoryBean mybatis spring provides MapperFactoryBean that can generate the implementation class of the mapper in the way of configuration and inject it into business components without writing DAO implementation classes
- Mappercannerconfigurer provided by mappercannerconfig mybatis spring will recursively scan all interfaces under the benchmark package (including sub packages at all levels). If they have been defined in the SQL mapping file, they will be dynamically registered as mapper implementation classes to generate mapper implementation classes in batch
2, Configure declarative transactions
What is a transaction?
Transaction is to treat a series of actions as an independent unit of work, which are either completed or ineffective. It is to execute a series of operations as atomicity.
Transaction has four attributes ACID:
1. Atomicity
A transaction is an atomic operation, which consists of a series of actions. The atomicity of a transaction ensures that the actions either complete or fail to work at all
2. Consistency
Once all the transaction actions are completed, the transaction will be committed. The data and resources are in a consistent state that meets the business rules
3. Isolation
Multiple transactions may process the same data at the same time, so each transaction should be isolated from other transactions to prevent data corruption
4. Durability
Once the transaction is completed, no matter what error occurs in the system, the transaction is closed
The results are not affected. Usually, the results of transactions are written to persistent memory
Implement transaction classification:
- Programming transaction management
Embed transaction management code into business methods to control transaction commit and rollback
Disadvantages: additional transaction management code must be included in each transaction operation business logic
- Declarative transaction management
In general, it is easier to use than programmatic transactions. The transaction management code is separated from business methods to realize transaction management in a declarative way. Transaction management is regarded as a crosscutting concern and modularized through AOP methods. Spring supports declarative transaction management through the Spring AOP framework
Transaction manager:
Spring's core transaction management abstraction encapsulates a set of technology independent methods. No matter which transaction management strategy (programmatic or declarative) spring uses, the transaction manager is necessary
How to configure declarative transactions in Spring?
preparation
add(SysUser sysUser) method is added to the SysUserMapper.java interface
package com.bdqn.dao; import com.bdqn.pojo.SysUser; import java.util.List; /** * SysUserMapper Data access layer interface * * @author Miku * @since 2021-05-14 */ public interface SysUserMapper { // Omit other code /** * Save user * @param sysUser * @return */ public int add(SysUser sysUser); }
A < insert id = "add" > node is added to the SysUserMapper.xml mapping file
<!-- Save user --> <insert id="add" parameterType="SysUser"> insert into t_sys_user (account, realName, password, sex, birthday, phone, address, roleId, createdUserId, createdTime) values (#{account}, #{realName}, #{password}, #{sex}, #{birthday}, #{phone}, #{address}, #{roleId}, #{createdUserId}, #{createdTime}) </insert>
add(SysUser sysUser) method is added to SysUserMapperImpl.java implementation class
package com.bdqn.dao; import com.bdqn.pojo.SysUser; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; /** * SysUserMapper Implementation class (operate the database through SqlSessionTemplate) * * @author Miku * @since 2021-05-14 */ public class SysUserMapperImpl implements SysUserMapper { // Omit other code /** * Save user * * @param sysUser * @return */ @Override public int add(SysUser sysUser) { return this.getSqlSession().getMapper(SysUserMapper.class).add(sysUser); } }
add(SysUser sysUser) method is added to the SysUserService.java interface
package com.bdqn.service; import com.bdqn.pojo.SysUser; import java.util.List; /** * SysUserService Service layer interface * * @author Miku * @since 2021-05-14 */ public interface SysUserService { // Omit other code /** * Save user * * @param sysUser * @return */ public boolean add(SysUser sysUser); }
add(SysUser sysUser) method is added to SysUserServiceImpl.java implementation class
package com.bdqn.service; import com.bdqn.dao.SysUserMapper; import com.bdqn.pojo.SysUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * SysUserService Service layer implementation class * * @author Miku * @since 2021-05-14 */ @Service("sysUserService") // Bean registered as a Service layer public class SysUserServiceImpl implements SysUserService { @Autowired // @Resource / / inject beans of DAO layer by annotation private SysUserMapper sysUserMapper; /** * Save user * * @param sysUser * @return */ // @Transactional(propagation = Propagation.REQUIRED) @Override public boolean add(SysUser sysUser) { // Simulate two operations on the database in a transaction. When an exception occurs after the first operation is completed, the second operation is not executed, and the first operation will also be rolled back. Both operations were either unsuccessful or successful at the same time sysUserMapper.add(sysUser); int num = 5 / 0; // Exception thrown in simulator // if (sysUser != null) { // Throw exception manually // throw new SendEMailException("send notification email exception"); // } sysUserMapper.add(sysUser); return true; } }
testAddUser method is added to SysUserTest.java test class
package com.bdqn; import com.bdqn.pojo.SysUser; import com.bdqn.service.SysUserService; import org.apache.log4j.Logger; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * SysUser Business test * * @author Miku * @since 2021-05-14 */ public class SysUserTest { // Omit other code /** * Test save user */ @Test public void testAddUser() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); SysUserService userService = (SysUserService) ctx.getBean("sysUserService"); SysUser user = new SysUser(); user.setAccount("test001"); user.setRealName("Test user 001"); user.setPassword("1234567"); Date birthday = null; try { birthday = new SimpleDateFormat("yyyy-MM-dd").parse("2021-05-17"); } catch (ParseException e) { e.printStackTrace(); } user.setBirthday(birthday); user.setAddress("Address test"); user.setSex(1); user.setPhone("13688783697"); user.setRoleId(1); user.setCreatedUserId(1); user.setCreatedTime(new Date()); boolean isok = userService.add(user); logger.debug("testAdd result: " + isok); } }
Method 1: write configuration for transaction configuration
Step 1: import namespace
This step can be automatically imported in IDEA by using the Alt+Enter shortcut when writing the configuration node.
applicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
The second step is to define the transaction manager
The transaction manager provides comprehensive support and unified management for transaction processing, which is equivalent to the role of enhanced processing in AOP. The configuration method is as follows:
applicationContext.xml
<!-- Declarative transaction configuration --> <!-- First, define the transaction manager (used here is JDBC Transaction manager, in addition to Java Primordial API Transaction manager JPA Transaction manager Hibernate Transaction manager, etc.) --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- Injection data source --> <property name="dataSource" ref="dataSource" /> </bean>
The transaction manager class DataSourceTransactionManager provided by the Spring framework is used here. It should be noted that when configuring the DataSourceTransactionManager, you should inject predefined data source components into it.
In addition, there are the following transaction configuration methods in different programming environments:
<!-- Define transaction manager Hibernate affair --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- Define transaction manager JPA affair --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- Define transaction manager Java Primordial API affair --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManagerName" value="java:/TransactionManager" /> </bean>
Step 3: set transaction attributes
The transaction manager can specify specific transaction rules for different business methods by setting transaction attributes.
applicationContext.xml
<!-- Declarative transaction configuration, which specifies specific transaction rules for different business methods( transaction-manager The default value of the property is transactionManager. That is, if the transaction manager Bean The name is transactionManager,You can not specify the attribute value) --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- Specify the properties of the transaction according to the method name, with an asterisk(*)Represents a wildcard --> <tx:method name="*"/> <!-- propagation Configure transaction propagation behavior --> <tx:method name="purchase" propagation="REQUIRES_NEW"/> <!-- isolation Configure the isolation level of the transaction --> <tx:method name="update*" isolation="SERIALIZABLE"/> <!-- rollback-for The configuration transaction encountered an exception and must be rolled back; no-rollback-for The configuration transaction encountered an exception and will not be rolled back --> <tx:method name="add*" rollback-for="java.io.IOException" no-rollback-for="com.bdqn.common.SendEMailException"/> <!-- read-only Configure transaction read-only properties --> <tx:method name="find*" read-only="true"/> <!-- timeout Configure the timeout attribute of the transaction --> <tx:method name="get*" timeout="3"/> </tx:attributes> </tx:advice>
Note: here, the transaction enhancement is configured through the < TX: advice > tag. The default value of the transaction manager attribute is transactionManager. That is, if the defined transaction manager Bean name is transactionManager, the attribute value can not be specified.
Transaction propagation mechanism, isolation level and other attributes can be configured in the < TX: attributes > tag. These attributes are set through the < TX: method > tag under the < TX: attributes > tag. The name attribute in the < TX: method > tag is required to specify the matching method, wildcard (*) Indicates that any character matches, and other attributes are optional. The specific features and usage are shown in the table below:
Transaction properties | explain |
name | Which methods need transaction control and support * wildcards |
propagation | Transaction propagation mechanism (generally, the first and second types are used more)
|
isolation | At the transaction isolation level, concurrent transactions can cause the following three types of problems
The difference between non repeatable reading and unreal reading: non repeatable reading focuses on the modification of the same data, while unreal reading is deletion or addition Theoretically, transactions should be completely isolated to avoid problems caused by concurrent transactions, but this may have a great impact on performance, because transactions must be carried out in order. Therefore, in actual development, transactions will run at a relatively low isolation level in order to improve performance. The isolation level of transactions in Spring can be specified through the isolation attribute:
Note: the isolation level of transactions needs the support of the underlying database engine, not the application or framework Oracle supports two transaction isolation levels: read_committed and serial MySQL supports four transaction isolation levels: READ_COMMITED,READ_UNCOMMITED,REPEATABLE_READ,SERIALIZABLE |
timeout | Transaction timeout The maximum time allowed for a transaction to run, in seconds (s), is automatically rolled back after a given time to prevent the transaction from taking too long to affect the system performance. This attribute needs the support of the underlying implementation. The default value is - 1, which means no timeout |
readonly | Boolean value, whether it is a read-only transaction
|
rollback-for | Exception type that can trigger rollback By default, the Spring framework identifies the transaction rollback only when the RuntimeException is thrown. You can specify the exception that needs to rollback the transaction through the fully qualified class name. Multiple class names are separated by English commas (,) |
no-rollback-for | Exception type that does not trigger rollback By default, CheckedException in the Spring framework will not trigger transaction rollback. You can specify the exceptions that need to roll back the transaction through the fully qualified class name. Multiple class names are separated by English commas |
Step 4: define the transaction aspect
By defining facets, transaction rules can be applied to specified methods.
applicationContext.xml
<!-- Define facets to associate transaction pointcuts with transaction attributes --> <aop:config> <!-- Define pointcuts expression="execution(* com.bdqn.service..*.*(..))" first[*]Represents any return value type;[com.bdqn.service..]Representative matching com.bdqn.service Package and its sub packages;[*.*(..)]Represents all methods that match all classes in the package --> <aop:pointcut id="serviceMethod" expression="execution(* com.bdqn.service..*.*(..))"/> <!-- Associate pointcuts with transaction attributes --> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" /> </aop:config>
Note: here, the transaction attribute component set by the < TX: advice > tag is referenced through the advice ref attribute of the < AOP: advisor > tag.
So far, the declarative transaction of the Spring framework is configured through the above four steps.
applicationContext.xml declarative transaction complete configuration
<!-- Declarative transaction configuration --> <!-- First, define the transaction manager (used here is JDBC Transaction manager, in addition to Java Primordial API Transaction manager JPA Transaction manager Hibernate Transaction manager, etc.) --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- Injection data source --> <property name="dataSource" ref="dataSource" /> </bean> <!-- Configure transaction attributes. Method 1: configure transactions by writing configuration --> <!-- Declarative transaction configuration, which specifies specific transaction rules for different business methods( transaction-manager The default value of the property is transactionManager. That is, if the transaction manager Bean The name is transactionManager,You can not specify the attribute value) --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- Specify the properties of the transaction according to the method name, with an asterisk(*)Represents a wildcard --> <tx:method name="*"/> <!-- propagation Configure transaction propagation behavior --> <tx:method name="purchase" propagation="REQUIRES_NEW"/> <!-- isolation Configure the isolation level of the transaction --> <tx:method name="update*" isolation="SERIALIZABLE"/> <!-- rollback-for The configuration transaction encountered an exception and must be rolled back; no-rollback-for The configuration transaction encountered an exception and will not be rolled back --> <tx:method name="add*" rollback-for="java.io.IOException" no-rollback-for="com.bdqn.common.SendEMailException"/> <!-- read-only Configure transaction read-only properties --> <tx:method name="find*" read-only="true"/> <!-- timeout Configure the timeout attribute of the transaction --> <tx:method name="get*" timeout="3"/> </tx:attributes> </tx:advice> <!-- Define facets to associate transaction pointcuts with transaction attributes --> <aop:config> <!-- Define pointcuts expression="execution(* com.bdqn.service..*.*(..))" first[*]Represents any return value type;[com.bdqn.service..]Representative matching com.bdqn.service Package and its sub packages;[*.*(..)]Represents all methods that match all classes in the package --> <aop:pointcut id="serviceMethod" expression="execution(* com.bdqn.service..*.*(..))"/> <!-- Associate pointcuts with transaction attributes --> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" /> </aop:config>
Among them, com.bdqn.common.SendEMailException is a custom exception type, which indicates an exception occurred when sending mail. The code is as follows:
SendEMailException.java
package com.bdqn.common; /** * Sending EMail exception * * @author Miku * @since 2021-05-14 */ public class SendEMailException extends RuntimeException { private static final long serialVersionUID = 1L; public SendEMailException(String message) { super(message); } public SendEMailException(Throwable cause) { super(cause); } public SendEMailException(String message, Throwable cause) { super(message, cause); } public SendEMailException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
Method 2: transaction configuration using annotations
In addition to using configuration files to handle transactions, the Spring framework also supports annotation with a small amount of configuration to handle declarative transactions. Compared with the pure configuration file method, the code written in this method is much simpler.
applicationContext.xml uses annotations for transaction configuration
<!-- Declarative transaction configuration --> <!-- First, define the transaction manager (used here is JDBC Transaction manager, in addition to Java Primordial API Transaction manager JPA Transaction manager Hibernate Transaction manager, etc.) --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- Injection data source --> <property name="dataSource" ref="dataSource" /> </bean> <!-- Enable the annotation transaction processing function. Method 2: use annotations for transaction configuration (note that the transaction manager still needs to be configured) --> <tx:annotation-driven />
Once the configuration file is written, you can use the @ Transactional annotation in your code to process transactions
SysUserServiceImpl.java
package com.bdqn.service; import com.bdqn.dao.SysUserMapper; import com.bdqn.pojo.SysUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; /** * SysUserService Service layer implementation class * * @author Miku * @since 2021-05-14 */ @Transactional @Service("sysUserService") public class SysUserServiceImpl implements SysUserService { @Autowired // @Resource private SysUserMapper sysUserMapper; @Transactional(propagation = Propagation.SUPPORTS) @Override public List<SysUser> getList(SysUser sysUser) { try { return sysUserMapper.selectSysUserList(sysUser); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } /** * Save user * * @param sysUser * @return */ @Transactional(propagation = Propagation.REQUIRED) @Override public boolean add(SysUser sysUser) { // Simulate two operations on the database in a transaction. When an exception occurs after the first operation is completed, the second operation is not executed, and the first operation will also be rolled back. Both operations are either unsuccessful or successful at the same time sysUserMapper.add(sysUser); int num = 5 / 0; // Exception thrown in simulator /*if (sysUser != null) { // Throw exception manually throw new SendEMailException("Sending notification email exception ""); }*/ sysUserMapper.add(sysUser); return true; } public SysUserMapper getSysUserMapper() { return sysUserMapper; } public void setSysUserMapper(SysUserMapper sysUserMapper) { this.sysUserMapper = sysUserMapper; } }
Test transaction
When executing the add test, either the two add operations succeed or fail at the same time. The test code is as follows:
SysUserTest.java executes the testAddUser() method
package com.bdqn; import com.bdqn.pojo.SysUser; import com.bdqn.service.SysUserService; import org.apache.log4j.Logger; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * SysUser Business test * * @author Miku * @since 2021-05-14 */ public class SysUserTest { private Logger logger = Logger.getLogger(SysUserTest.class); @Before public void setUp() throws Exception { } /** * Test get user list */ @Test public void testGetUserList() { // Multiple configuration files can be loaded at the same time; other configurations can also be imported in the main configuration file applicationContext.xml (recommended) // String[] confs = {"applicationContext.xml","applicationContext-dao.xml","applicationContext-service.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); SysUserService userService = (SysUserService) ctx.getBean("sysUserService"); List<SysUser> userList = new ArrayList<SysUser>(); SysUser sysUser = new SysUser(); sysUser.setRealName("Zhao"); sysUser.setRoleId(2); userList = userService.getList(sysUser); for (SysUser userResult : userList) { logger.debug("testGetUserList account: " + userResult.getAccount() + " and realName: " + userResult.getRealName() + " and roleId: " + userResult.getRoleId() + " and roleName: " + userResult.getRoleIdName() + " and address: " + userResult.getAddress()); } } /** * Test save user */ @Test public void testAddUser() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); SysUserService userService = (SysUserService) ctx.getBean("sysUserService"); SysUser user = new SysUser(); user.setAccount("test001"); user.setRealName("Test user 001"); user.setPassword("1234567"); Date birthday = null; try { birthday = new SimpleDateFormat("yyyy-MM-dd").parse("2021-05-17"); } catch (ParseException e) { e.printStackTrace(); } user.setBirthday(birthday); user.setAddress("Address test"); user.setSex(1); user.setPhone("13688783697"); user.setRoleId(1); user.setCreatedUserId(1); user.setCreatedTime(new Date()); boolean isok = userService.add(user); logger.debug("testAdd result: " + isok); } }
Execute the test case, view the data in the database, and find that the transaction works.