There are many limitations when using mybatis alone (such as not being able to implement transactions spanning multiple sessions), and many business systems are originally transactions managed by spring, so mybatis is best integrated with spring.
Version Requirements
project | Version | Download address | illustrate |
mybatis | 3.0 and above | https://github.com/mybatis/mybatis-3/releases | |
spring | 3.0 and above | http://projects.spring.io/spring-framework/ | |
mybatis-spring | 1.0 and above | https://github.com/mybatis/spring/releases |
<!-- Automatic scanning of business packages--> <context:component-scan base-package="com.xxx.service" /> <!-- Data source--> <jee:jndi-lookup id="jndiDataSource" jndi-name="java:comp/env/jdbc/datasource" /> <!-- Configure transaction--> <bean id="txManager" > <property name="dataSource" ref="jndiDataSource" /> </bean> <!-- Configure annotation-based things aop --> <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
Single integration
<!-- Integration of mybatis --> <bean id="sqlSessionFactory"> <property name="dataSource" ref="jndiDataSource" /> <property name="configLocation" value="classpath:/mybatis/mybatis-config.xml" /> <!-- Automatic configuration alias --> <property name="typeAliasesPackage" value="com.xxx.dto" /> </bean> <!-- Create dao bean (just provide interfaces but not implementation classes) --> <bean id="userDao"> <property name="mapperInterface" value="com.xxx.dao.UserDao" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
We must not only understand how to use it, but also understand why we use it like this.
SqlSessionFactoryBean is a factory bean, and its function is to parse configurations (data source, alias, etc.).
MapperFactoryBean is a factory bean. In spring container, factory beans have special uses. When spring injects factory beans into other beans, it does not inject the factory bean itself but calls the bean's getObject method. Let's take a look at what this getObject method does:
public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); }After seeing this, you should understand that this method is the same as when we used Mybatis alone. We first get a Sqlsession object, and then get the Mapper object from the Sqlsession (against the Mapper is a proxy object, which proxies the mapper Interface interface, and this interface is the dao interface provided by the user). Naturally, the final injection into the business layer is this Mapper object.
Generally speaking, there are more than one project. If you have multiple projects, then configure them in sequence according to the above configuration.
How to use batch updates
The previous section talked about how to inject a mapper object into the business layer. The behavior of mapper depends on configuration. Mybatis uses a single update by default (that is, the default ExecutorType is SIMPLE instead of BATCH). Of course, we can modify the default behavior by modifying the mybatis configuration file, but if we only want one or several mappers to use batch updates, it cannot be done. At this time, we need to use template technology:
<!--Customize the behavior of mybatis through templates-> lt;bean id="sqlSessionTemplateSimple"> <constructor-arg index="0" ref="sqlSessionFactory" /> <!--Update in a single mode--> <constructor-arg index="1" value="SIMPLE"/> </bean> <!--Customize the behavior of mybatis through templates--> lt;bean id="sqlSessionTemplateBatch"> <constructor-arg index="0" ref="sqlSessionFactory" /> <!--Update in a batch mode--> <constructor-arg index="1" value="BATCH"/> </bean>
Here, the author defines two template objects, one using a single update and the other using batch update. After we have the template, we can change the way mapper behaves:
<bean id="userDao"> <property name="mapperInterface" value="com.xxx.dao.UserDao" /> <property name="sqlSessionTemplate" ref="sqlSessionTemplateBatch " /> </bean>
Different from the mapper configuration in the previous section, there is no need to configure the sqlSessionFactory property here, you only need to configure the sqlSessionTemplate (the sqlSessionFactory property has been configured in the template).
Simplify the configuration of mappers with automatic scanning
As you can see in the previous chapter, our dao needs to be configured one by one in the configuration file. If there are many dao, the configuration file will be very large, which will be more painful to manage. Fortunately, the mybatis team also realized this. They used the automatic scanning function provided by spring to encapsulate a tool class that automatically scans, so that we can use this function to simplify the configuration:
<!-- Create mapper bean using automatic scanning (single update mode) --> <bean> <property name="basePackage" value="com.xxx.dao" /> <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplateSimple" /> <property name="markerInterface" value="com.xxx.dao.SimpleDao" /> </bean> <!-- Create mapper bean using automatic scanning (batch update mode) --> <bean> <property name="basePackage" value="com.xxx.dao" /> <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplateBatch" /> <property name="markerInterface" value="com.xxx.dao.BatchDao" /> </bean>
I won't talk about the spring technology involved in MapperScannerConfigurer itself. If you are interested and have a good understanding of the principles of spring, you can check its source code. Let's focus on its three properties:
In addition to using interface filtering, you can also use annotation filtering:
<!-- Create mapper bean using automatic scanning (batch update mode) --> <bean> <property name="basePackage" value="com.xxx.dao" /> <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplateBatch" /> <property name="annotationClass" value="com.xxx.dao.BatchAnnotation" /> </bean>
annotationClass: Only when the annotation is configured will it be scanned by the scanner, and the basePackage is the function of the same.
It should be noted that only one of the two filter conditions can be matched.
Example: Transaction Management
Define an entity class:Emp.java
package com.lixing.scm.entity;public class Emp { private String id; private String name; private String sex; private int age; private String phone; 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 String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; }} Define the internal operation interface: EmpMapper.java
package com.lixing.scm.test.mapper;import java.util.List;import java.util.Map;import com.lixing.scm.entity.Emp;public interface EmpMapper { void insertEmp(Emp emp); List<Emp> getAllEmp(); Emp getById(String id); void deleteEmp(String id); void updateEmp(Map<String,Object> map);} Define the mapping file for the entity class operation interface: EmpMapper.xml
<?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 namespace="com.lixing.scm.test.mapper.EmpMapper"> <parameterMap type="com.lixing.scm.entity.Emp" id="parameterMapEmp"> <parameter property="id"/> <parameter property="name"/> <parameter property="sex"/> <parameter property="age"/> <parameter property="phone"/> </parameterMap> <resultMap type="com.lixing.scm.entity.Emp" id="resultMapEmp"> <result property="id" column="id"/> <result property="name" column="name"/> <result property="sex" column="sex"/> <result property="age"/> <result property="age" column="age"/> <result property="phone"/> </resultMap> <insert id="insertEmp" parameterMap="parameterMapEmp"> INSERT INTO emp(id,name,sex,age,phone) VALUES(?,?,?,?,?) </insert> <select id="getAllEmp" resultMap="resultMapEmp"> SELECT * FROM emp </select> <select id="getById" parameterType="String" resultMap="resultMapEmp"> SELECT * FROM emp WHERE id=#{value} </select> <delete id="deleteEmp" parameterType="String"> DELETE FROM emp WHERE id=#{value} </delete> <update id="updateEmp" parameterType="java.util.Map"> UPDATE emp SET name=#{name},sex=#{sex},age=#{age},phone=#{phone} WHERE id=#{id} </update></mapper>Spring3.0.6 definition: 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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- --> <context:annotation-config /> <context:component-scan base-package="com.lixing.scm.test.*" /> <!-- jdbc.propertis Directory --> <bean > <property name="locations" value="classpath:jdbc.properties" /> </bean> <bean id="MyDataSource" destroy-method="close" > <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- SqlSessionFactory --> <bean id="sqlSessionFactory"> <property name="dataSource" ref="MyDataSource" /> </bean> <!-- ScanMapperFiles --> <bean> <property name="basePackage" value="com.lixing.scm.test.mapper" /> </bean> <!-- ================================================================================================================== --> <bean name="transactionManager"> <property name="dataSource" ref="MyDataSource"></property> </bean> <tx:advice id="userTxAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException"/> <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.RuntimeException" /> <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="find*" propagation="SUPPORTS"/> <tx:method name="get*" propagation="SUPPORTS"/> <tx:method name="select*" propagation="SUPPORTS"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pc" expression="execution(public * com.lixing.scm.test.service.*.*(..))" /> <!--Control transactions at the Service level--> <aop:advisor pointcut-ref="pc" advice-ref="userTxAdvice" /> </aop:config> <!-- The following is a custom Bean--> <bean id="empDao" autowire="byName" /> <bean id="empService" autowire="byName"/></beans> DAO interface:EmpDAO.java
package com.lixing.scm.test.dao;import java.util.List;import java.util.Map;import com.lixing.scm.entity.Emp;public interface EmpDao { void insertEmp(Emp emp); List<Emp> getAllEmp(); Emp getById(String id); void deleteEmp(String id); void updateEmp(Map<String, Object> map);} DAO interface implementation class: EmpDaoImpl.java
package com.lixing.scm.test.dao.impl;import java.util.List;import java.util.Map;import com.lixing.scm.entity.Emp;import com.lixing.scm.test.dao.EmpDao;import com.lixing.scm.test.mapper.EmpMapper;public class EmpDaoImpl implements EmpDao { private EmpMapper empMapper; //Inject an empMapper here //This empMapper is automatically generated by Spring//We do not need to manually define @Override public void insertEmp(Emp emp) { this.empMapper.insertEmp(emp); throw new RuntimeException("Error"); //Test throws RuntimeException //Exception to see if the database has records} @Override public void deleteEmp(String id) { this.empMapper.deleteEmp(id); } @Override public List<Emp> getAllEmp() { return this.empMapper.getAllEmp(); } @Override public Emp getById(String id) { return this.empMapper.getById(id); } @Override public void updateEmp(Map<String, Object> map) { this.empMapper.updateEmp(map); } public EmpMapper getEmpMapper() { return empMapper; } public void setEmpMapper(EmpMapper empMapper) { this.empMapper = empMapper; }} Service layer interface:EmpService.java
package com.lixing.scm.test.service;import com.lixing.scm.entity.Emp;public interface EmpService { void insertEmp(Emp emp);} Service layer interface implementation class:EmpServiceImpl.java
package com.lixing.scm.test.service.impl;import com.lixing.scm.entity.Emp;import com.lixing.scm.test.dao.EmpDao;import com.lixing.scm.test.service.EmpService;public class EmpServiceImpl implements EmpService { private EmpDao empDao; @Override public void insertEmp(Emp emp) { empDao.insertEmp(emp); } public EmpDao getEmpDao() { return empDao; } public void setEmpDao(EmpDao empDao) { this.empDao = empDao; }} Test class: TestEmpService.java
import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.lixing.scm.entity.Emp;import com.lixing.scm.test.service.EmpService;public class TestEmpService { @Test public void testTrasaction(){ Emp emp=new Emp(); emp.setId("00000003"); emp.setName("某某某"); emp.setAge(50); emp.setSex("Male"); emp.setPhone("566666"); ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); EmpService service=ctx.getBean(EmpService.class); service.insertEmp(emp); }}