1 導入jar包 1.1 導入Spring的開發包 1.2 導入mybatis的jar包 1.3 導入MySQL的驅動 1.4 導入mybatis與Spring的整合包 1.5 導入junit4.jar包 1.6 導入log4j.jar 1.5 導入c3p0.jar 1.6 導入spring-tes ...
1 導入jar包
1.1 導入Spring的開發包
1.2 導入mybatis的jar包
1.3 導入MySQL的驅動
1.4 導入mybatis與Spring的整合包
1.5 導入junit4.jar包
1.6 導入log4j.jar
1.5 導入c3p0.jar
1.6 導入spring-test.jar包
2 Mybatis整合Spring方式一(原始DAO方式)
2.1 導入log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=off, stdout
2.1 新建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> <mappers> <mapper resource="cn/dao/EmployeeMapper.xml"/> </mappers> </configuration>
2.2 新建資料庫及數據表
create database ssm; use database ssm; create table employee( id int(11) primary key auto_increment, last_name varchar(255) , gender varchar(255), emailvarchar(255) );
2.3 新建pojo及mybatis的映射文件
2.3.1 Employee.java
package cn.domain; /** * 描述: */ public class Employee { private Integer id; private String lastName; private String email; private String gender; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } }
2.2.1 建立映射文件 EmployeeMapper.xml--和Employee.java在同一個包下
<?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="cn.dao.IEmployeeDAO"> <select id="getEmployeeById" resultMap="cn.domain.Employee" parameterType="java.lang.Integer"> select * from employee where id = #{id} </select> </mapper>
2.2.2 建立jdbc.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=root
2.2.3 新建數據訪問層介面--IEmployeeDAO.java
package cn.dao; import cn.domain.Employee; /** * 描述: */ public interface IEmployeeDAO { public Employee getEmployeeById(Integer id); }
2.3.4 新建EmployeeDAO.java實現類
package cn.dao; import cn.domain.Employee; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.support.SqlSessionDaoSupport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; /** * 描述: */ @Repository(IEmployeeDAO.DAO_NAME) public class EmployeeDAOImpl extends SqlSessionDaoSupport implements IEmployeeDAO { /** * 註入sqlSessionFactory * @param sqlSessionFactory */ @Autowired @Qualifier(value = "sqlSessionFactory") public void sessionFacotryDI(SqlSessionFactory sqlSessionFactory){ super.setSqlSessionFactory(sqlSessionFactory); } @Override public Employee getEmployeeById(Integer id) { return this.getSqlSession().selectOne("cn.dao.IEmployeeDAO.getEmployeeById",id); } }
2.2.5 新建mybatis-config.xml文件---mybatis的核心配置文件
<?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> <mappers> <mapper resource="cn/dao/EmployeeMapper.xml"/> </mappers> </configuration>
2.2.6 在web.xml文件中配置如下信息
<!-- Spring的配置 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
為什麼要如此配置,主要是為了讓伺服器一啟動的時候就載入applicationContext.xml文件。我們可以這樣想,我們平時測試spring框架的時候,是不是都是使用如下代碼:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Bean bean = (Bean)applicationContext.getBean("bean的id");
而
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
其實就是載入Spring的環境,但是如果我們在業務層或者控制層一直這麼乾,那我們就完蛋了,伺服器要不停的載入Spring的環境,怎麼辦尼?我們想到了ServletContext對象,這個對象就是伺服器啟動時載入並且只載入一次,那麼如果我們將上面的那段代碼放入ServletContext的域之中,那麼讓伺服器啟動的時候來載入Spring的環境,是不是非常棒尼。就是如此.當然這邊配置的是監聽器是用來監聽ServletContext對象的,一旦它創建,就讓Spring的環境信息放到ServletContext對象域之中,所以,spring-web.jar包就是這麼乾的。這也就是我們整合其他web框架,如Struts2等,需要增加spring-web.jar的原因,當然,整合Struts2還需要其他jar包,這裡不一一闡述。
2.2.7 新建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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 載入資料庫的信息 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 註解掃描 --> <context:component-scan base-package="cn"/> <!-- 配置數據源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- Spring管理:sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 數據源 --> <property name="dataSource" ref="dataSource"/> <!-- mybatis的核心配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <!-- 事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 開啟事務的驅動 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
2.2.8 新建service層的介面--IEmployeeService.java
package cn.service; import cn.domain.Employee; /** * 描述: */ public interface IEmployeeService { public static final String SERVICE_Name = "cn.service.EmployeeServiceImpl"; public Employee getEmployeeById(Integer id); }
2.2.9 新建Service層的實現類--EmployeeServiceImpl.java
package cn.service; import cn.dao.IEmployeeDAO; import cn.domain.Employee; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; /** * 描述: */ @Service(value = IEmployeeService.SERVICE_Name) @Transactional public class EmployeeServiceImpl implements IEmployeeService { @Resource(name = IEmployeeDAO.DAO_NAME) private IEmployeeDAO employeeDAO; @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = true) @Override public Employee getEmployeeById(Integer id) { return this.employeeDAO.getEmployeeById(id); } }
2.2.10 測試
package cn.Test; import cn.domain.Employee; import cn.service.IEmployeeService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; /** * 描述: */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class EmployeeTest { @Resource(name = IEmployeeService.SERVICE_Name) private IEmployeeService employeeService; @Test public void demo1(){ Employee employee = employeeService.getEmployeeById(1); System.out.print(employee.getLastName()+" "+employee.getGender()+" "+employee.getEmail()); } }
2.2.11 提示
- 當然,如果你安裝上面的步驟,是得不到數據的,因為你資料庫之中是沒有數據的,那麼,就在你資料庫之中插入數據吧。
- 其實,這種整合方式,和Spring+Hibernate的方式如出一轍,思路等等都是一樣,只是類等不同而已。
3 Spring整合Mybatis方式二(Mapper介面,MapperFactory類)
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.mybatis.spring.mapper; import org.apache.ibatis.executor.ErrorContext; import org.apache.ibatis.session.Configuration; import org.mybatis.spring.support.SqlSessionDaoSupport; import org.springframework.beans.factory.FactoryBean; import org.springframework.util.Assert; public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { private Class<T> mapperInterface; private boolean addToConfig = true; public MapperFactoryBean() { } public MapperFactoryBean(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } protected void checkDaoConfig() { super.checkDaoConfig(); Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = this.getSqlSession().getConfiguration(); if(this.addToConfig && !configuration.hasMapper(this.mapperInterface)) { try { configuration.addMapper(this.mapperInterface); } catch (Exception var6) { this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6); throw new IllegalArgumentException(var6); } finally { ErrorContext.instance().reset(); } } } public T getObject() throws Exception { return this.getSqlSession().getMapper(this.mapperInterface); } public Class<T> getObjectType() { return this.mapperInterface; } public boolean isSingleton() { return true; } public void setMapperInterface(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } public Class<T> getMapperInterface() { return this.mapperInterface; } public void setAddToConfig(boolean addToConfig) { this.addToConfig = addToConfig; } public boolean isAddToConfig() { return this.addToConfig; } }
- 使用Spring整合Mybatis的原理其實就是以下的代碼,當然這是Mybatis3以前的寫法
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); Employee employee = session.selectOne("default.findById", 1); System.out.print(employee); session.close();
但是,在Mybatis3之後,官方不再推薦此種寫法,因為這種寫法的代碼模板很重覆,所以Mybatis3之後推薦下麵的寫法,這也是Spring整合Mybatis的理論來源之一。
package cn.demo1; public interface IEmployeeDAO { public Employee findById(Integer id); }
<?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="cn.demo1.IEmployeeDAO"> <!-- namespace:命名空間 指定為介面的全類名 id:唯一標識 和介面中的方法名相同 resultType:返回值類型 --> <select id="findById" parameterType="int" resultType="cn.demo1.Employee"> select id,last_name lastName,email,gender from employee where id = #{id} </select> </mapper>
package cn.test; import cn.demo1.Employee; import cn.demo1.IEmployeeDAO; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.IOException; import java.io.InputStream; /** * * 描述: */ public class MybatisTest { @Test public void demo1() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); IEmployeeDAO dao = session.getMapper(IEmployeeDAO.class); Employee employee = dao.findById(1); System.out.print(employee); session.close(); } }
- 我們觀察上面的測試代碼,可以看出此種寫法不需要寫實現類,實現類完全由Mybatis給我們生成,其實就是代理類了。當然必須遵循一定的規則,規則在此處就不闡述了。
- 我們可以看到sqlsession.getMapper(Class clazz)傳入的是一個介面的Class類型,那麼我們觀察MapperFactoryBean是不是裡面有一個mapperInterface的屬性,那麼我們只要向其中註入介面不就可以了,同時MapperFactoryBean還繼承了SqlsessionFactorySupport類,那麼我們再向MapperFactoryBean中註入sqlSessionFactory就可以了。
- 所以: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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 載入資料庫的信息 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 註解掃描 --> <context:component-scan base-package="cn"/> <!-- 配置數據源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- Spring管理:sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 數據源 --> <property name="dataSource" ref="dataSource"/> <!-- mybatis的核心配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <!-- 事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 開啟事務的驅動 --> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 配置Mapper MapperFactoryBean用於生成代理對象 --> <bean id="employeeMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="cn.dao.EmployeeMapper"/> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> </beans>
- 當然此時刪除那些原始的DAO介面和實現類哦,新建EmployeeMapper.java介面
package cn.dao; import cn.domain.Employee; /** * 描述: */ public interface EmployeeMapper { public Employee getEmployeeById(Integer id); }
- EmployeeMapper.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="cn.dao.EmployeeMapper"> <resultMap id="emp" type="cn.domain.Employee"> <id property="id" column="id"/> <result property="lastName" column="last_name"/> <result property="email" column="email"/> <result property="gender" column="gender"/> </resultMap> <select id="getEmployeeById" resultMap="emp" parameterType="java.lang.Integer"> select id,last_name,email,gender from employee where id = #{id} </select> </mapper>
- IEmployeeService.java
package cn.service; import cn.domain.Employee; /** * 描述: */ public interface IEmployeeService { public static final String SERVICE_Name = "cn.service.EmployeeServiceImpl"; public Employee getEmployeeById(Integer id); }
- EmployeeServiceImpl.java
package cn.service; import cn.dao.EmployeeMapper; import cn.domain.Employee; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; /** * 描述: */ @Service(value = IEmployeeService.SERVICE_Name) @Transactional public class EmployeeServiceImpl implements IEmployeeService { @Resource(name = "employeeMapper") private EmployeeMapper employeeMapper; @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = false) @Override public Employee getEmployeeById(Integer id) { return employeeMapper.getEmployeeById(id); } }
- 測試類
package cn.Test; import cn.domain.Employee; import cn.service.IEmployeeService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; import java.io.IOException; /** * 描述: */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class EmployeeTest { @Resource(name = IEmployeeService.SERVICE_Name) private IEmployeeService employeeService; @Test public void demo1() throws IOException { Employee employee = employeeService.getEmployeeById(1); System.out.print(employee.getLastName()+" "+employee.getEmail()+" "+employee.getGender()); } }
- 當然如果你使用此種方式,一旦你的DAO的介面(mybatis中稱為Mapper)太多了,那麼你applicationContext.xml會充滿了太多這種什麼尼?答案就是每個Mapper你都需要配置,my god 太繁瑣了。
4 Spring整合Mybatis三(Mapper介面,MapperScannerConfigurer類)
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.mybatis.spring.mapper; import java.lang.annotation.Annotation; import java.util.Iterator; import java.util.Map; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.PropertyResourceConfigurer; import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.GenericApplicationContext; import org.springframework.util.Assert; import org.springframework.util.StringUtils; public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { private String basePackage; private boolean addToConfig = true; private SqlSessionFactory sqlSessionFactory;