今天是mybatis的最后一天,也是最为重要的一天,mybatis与spring整合,(spring相关知识我会抽一个大的模块进行讲解).
首先加入Spring的依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> <!-- Mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </dependency> <!-- 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>0.9.1</version> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <!-- Mybatis 和 Spring整合包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> </dependency> <!-- 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency>
先创建applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 使用spring自带的占位符替换功能 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <!-- 允许JVM参数覆盖 --> <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> <!-- 忽略没有找到的资源文件 --> <property name="ignoreResourceNotFound" value="true" /> <!-- 配置资源文件 --> <property name="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> </bean> <context:component-scan base-package="com.j1"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据库驱动 --> <property name="driverClassName" value="${jdbc.driver}" /> <!-- 基本属性 url、user、password --> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- 配置初始化大小、最小、最大 --> <property name="initialSize" value="10" /> <property name="minIdle" value="5" /> <property name="maxActive" value="50" /> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000" /> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000" /> <property name="validationQuery" value="SELECT 1" /> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <!-- 打开PSCache,并且指定每个连接上PSCache的大小 --> <!-- 如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。分库分表较多的数据库,建议配置为false。 --> <property name="poolPreparedStatements" value="false" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> <!-- 配置监控统计拦截的filters --> <property name="filters" value="stat" /> </bean> <!-- 构造sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 指定Mybatis的配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml"></property> </bean> <!-- 定义Mapper --> <bean id="orderMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <!-- 指定接口 --> <property name="mapperInterface" value="com.j1.mybatis.mapper.OrderMapper" /> <!-- 指定sqlSessionFactory --> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean> </beans>
通过Spring 来获得OrderMapper
private OrderMapper orderMapper; @Before public void setUp() throws Exception { try { /** * 这是之前的写法,现在我们来集成Spring做这件事情,就会很简单 * // 构造SqlSessionFactory // 定义配置文件路径 String resource = "mybatis-config.xml"; // 读取配置文件 InputStream inputStream = Resources.getResourceAsStream(resource); // 通过SqlSessionFactoryBuilder构建一个SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream); // this.userDAO = new UserDao(sqlSessionFactory); SqlSession sqlSession = sqlSessionFactory.openSession(true); this.orderMapper = sqlSession.getMapper(OrderMapper.class); */ ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); this.orderMapper=context.getBean(OrderMapper.class); } catch (Exception e) { e.printStackTrace(); } }
进行测试:
/** * 一对一的第二种查询 */ @Test public void testQuerOrderAndUserByOrderNum2() { Order order = orderMapper.querOrderAndUserByOrderNum2("20140921002"); System.out.println(order); }
/** * 根据订单号查询订单并且查询出下单人的信息,第二种实现 * * @param orderNumber * @return */ public Order querOrderAndUserByOrderNum2(String orderNum);
<!-- 一对一的第二种查询方法,进行映射 --> <resultMap id="orderMap" type="Order" autoMapping="true"> <id column="id" property="id"/> <association property="user" javaType="User" autoMapping="true"> </association> </resultMap> <select id="querOrderAndUserByOrderNum2" resultMap="orderMap"> SELECT o.*, u.name, u.user_name, u.age FROM tb_order o LEFT JOIN tb_user u ON u.id = o.user_id WHERE o.order_number = #{orderNumber} </select>
这套代码运行下来,初级的Spring的整合就结束了.
接着我们来整理applicationContext.xml,使其更加简明扼要.
<!-- 定义Mybatis mapper接口扫描器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.j1.mybatis.mapper" /> </bean>
<!-- 构造sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 指定Mybatis的配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml"></property> <!-- 使用通配符配置mapper.xml --> <property name="mapperLocations" value="classpath:mappers/*.xml"></property> </bean>
如果指定了mapper不需要定义接口扫描,如果xml与mapper的java代码分离的话就必须定义接口扫描器,否则或报错.
1.1. Mapper整合Service
package com.j1.mybatis.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.j1.mybatis.mapper.OrderMapper; import com.j1.mybatis.pojo.Order; @Service public class OrderService { @Autowired private OrderMapper orderMapper; public Order querOrderAndUserByOrderNum2(String orderNum){ return orderMapper.querOrderAndUserByOrderNum2(orderNum); } }
package com.j1.mybatis.mapper; import static org.junit.Assert.*; import java.io.IOException; import java.io.InputStream; 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.aspectj.apache.bcel.util.ClassPath; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.j1.mybatis.pojo.Order; import com.j1.mybatis.pojo.OrderUser; import com.j1.mybatis.pojo.User; import com.j1.mybatis.service.OrderService; public class OrderMapperTest { private OrderMapper orderMapper; private OrderService orderService; @Before public void setUp() throws Exception { try { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); this.orderService=context.getBean(OrderService.class); } catch (Exception e) { e.printStackTrace(); } } /** * 一对一查询的第一种方法 */ @Test public void testQuerOrderAndUserByOrderNumY() { OrderUser orderUser = this.orderMapper .querOrderAndUserByOrderNumY("20140921002"); System.out.println(orderUser); } /** * 一对一的第二种查询 */ @Test public void testQuerOrderAndUserByOrderNum2() { // Order order = orderMapper.querOrderAndUserByOrderNum2("20140921002"); Order order=orderService.querOrderAndUserByOrderNum2("20140921002"); System.out.println(order); } /** * 一对多的查询 */ @Test public void queryOrderAndUserAndOrderDetailByOrderNumber() { Order order = orderMapper .queryOrderAndUserAndOrderDetailByOrderNumber("20140921002"); System.out.println(order); } /** * 多对多的查询 */ @Test public void testQueryOrderAndUserAndOrderDetailAndItemByOrderNumber() { Order order = this.orderMapper .queryOrderAndUserAndOrderDetailAndItemByOrderNumber("20140921001"); System.out.println(order); } }
1. 整合spring事务管理
为什么要整合Spring的事务管理呢?
先分析一下,其实这和mybatis没任何关系,只是事务管理用Spring来进行管理罢了.
创建applicationContext-transaction.xml文件,
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 定义事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 定义事务策略 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--所有以query开头的方法都是只读的 --> <tx:method name="query*" read-only="true" /> <!--其他方法使用默认事务策略 --> <tx:method name="*" /> </tx:attributes> </tx:advice> <aop:config> <!--pointcut元素定义一个切入点,execution中的第一个星号 用以匹配方法的返回类型, 这里星号表明匹配所有返回类型。 com.abc.dao.*.*(..)表明匹配com.j1.mybatis.service包下的所有类的所有 方法 --> <aop:pointcut id="myPointcut" expression="execution(* com.j1.mybatis.*.*(..))" /> <!--将定义好的事务处理策略应用到上述的切入点 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" /> </aop:config> </beans>
package com.j1.mybatis.service; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.j1.mybatis.pojo.Order; public class OrderServiceTest { private OrderService orderService; @Before public void setUp() throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml","applicationContext-transaction.xml"}); this.orderService = context.getBean(OrderService.class); } @Test public void querOrderAndUserByOrderNum2() { Order order = this.orderService.querOrderAndUserByOrderNum2("20140921001"); System.out.println(order); } }
log如下:
2016-09-21 21:56:08,886 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Creating instance of bean '(inner bean)#2369fbfa' 2016-09-21 21:56:08,886 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' 2016-09-21 21:56:08,896 [main] [org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource]-[DEBUG] Adding transactional method [query*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly] 2016-09-21 21:56:08,896 [main] [org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource]-[DEBUG] Adding transactional method [*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT] 2016-09-21 21:56:08,897 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' 2016-09-21 21:56:08,897 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' 2016-09-21 21:56:08,901 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Finished creating instance of bean '(inner bean)#2369fbfa' 2016-09-21 21:56:08,902 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Invoking afterPropertiesSet() on bean with name 'txAdvice' 2016-09-21 21:56:08,902 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Finished creating instance of bean 'txAdvice' 2016-09-21 21:56:08,902 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 2016-09-21 21:56:08,902 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' 2016-09-21 21:56:08,902 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor' 2016-09-21 21:56:08,903 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor' 2016-09-21 21:56:08,903 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'orderMapper' 2016-09-21 21:56:08,903 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'userMapper' 2016-09-21 21:56:08,906 [main] [org.springframework.context.support.ClassPathXmlApplicationContext]-[DEBUG] Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@3fc12084] 2016-09-21 21:56:08,907 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'lifecycleProcessor' 2016-09-21 21:56:08,911 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'sqlSessionFactory' 2016-09-21 21:56:08,913 [main] [org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties] 2016-09-21 21:56:08,914 [main] [org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment] 2016-09-21 21:56:08,914 [main] [org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null] 2016-09-21 21:56:08,915 [main] [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean 'orderService' 2016-09-21 21:56:08,932 [main] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Creating a new SqlSession 2016-09-21 21:56:08,956 [main] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6848db81] was not registered for synchronization because synchronization is not active 2016-09-21 21:56:08,976 [main] [org.springframework.jdbc.datasource.DataSourceUtils]-[DEBUG] Fetching JDBC Connection from DataSource 2016-09-21 21:56:08,988 [main] [org.mybatis.spring.transaction.SpringManagedTransaction]-[DEBUG] JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@c59de6f] will not be managed by Spring 2016-09-21 21:56:09,001 [main] [com.j1.mybatis.mapper.OrderMapper.querOrderAndUserByOrderNum2]-[DEBUG] ==> Preparing: SELECT o.*, u.name, u.user_name, u.age FROM tb_order o LEFT JOIN tb_user u ON u.id = o.user_id WHERE o.order_number = ? 2016-09-21 21:56:09,107 [main] [com.j1.mybatis.mapper.OrderMapper.querOrderAndUserByOrderNum2]-[DEBUG] ==> Parameters: 20140921001(String) 2016-09-21 21:56:09,264 [main] [com.j1.mybatis.mapper.OrderMapper.querOrderAndUserByOrderNum2]-[DEBUG] <== Total: 1 2016-09-21 21:56:09,264 [main] [com.alibaba.druid.pool.PreparedStatementPool]-[DEBUG] {conn-10010, pstmt-20000} enter cache 2016-09-21 21:56:09,278 [main] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6848db81] 2016-09-21 21:56:09,279 [main] [org.springframework.jdbc.datasource.DataSourceUtils]-[DEBUG] Returning JDBC Connection to DataSource Order [id=1, userId=1, orderNumber=20140921001, user=User [id=1, userName=zhangsan, password=null, name=张三, age=30, sex=null, birthday=null, created=null, updated=null]]
好了,至此,mybatis已全部结束,有问题,大家在一起沟通,互相交流