第六章 MyBatis 与Spring 整合

第六章 MyBatis 与Spring 整合

持久层整合

(1)Spring为什么要与持久层整合

1.JavaEE开发需要持久层进行数据库访问操作
2.JDBC  hibernate  MyBatis进行持久开发又大量的代码冗余
3.Spring基于模板设计模式对于上述持久层技术进行了封装

(2)Spring 与 持久层整合?

1.JDBC  -- JDBCTemplate
2.Hibernate(JPA)  -- HibernateTemplate
3.MyBatis  -- SqlSessionFactoryBean
		   -- MapperScannerConfigure

MyBatis 在开发中存在的问题

配置繁琐 代码冗余
1. 实体
2. 实体别名  配置繁琐
3. 表
4. 创建DAO接⼝
5. 实现Mapper⽂件
6. 注册Mapper⽂件 配置繁琐
7. MybatisAPI调⽤ 代码冗余

Spring与MyBatis整合思路分析

在这里插入图片描述

Spring 和MyBatis 整合开发

(1)环境搭建

gradle 添加如下包依赖

// https://mvnrepository.com/artifact/org.springframework/spring-jdbc
compile group: 'org.springframework', name: 'spring-jdbc', version: '5.2.0.RELEASE'

compile group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.4'


// https://mvnrepository.com/artifact/com.alibaba/druid
compile group: 'com.alibaba', name: 'druid', version: '1.1.21'


compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.18'

// https://mvnrepository.com/artifact/org.mybatis/mybatis
compile group: 'org.mybatis', name: 'mybatis', version: '3.4.6'

(2)Spring配置文件配置

<?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 http://www.springframework.org/schema/context/spring-context.xsd">

<!--
   <context:property-placeholder location="db.properties"/>
-->
    <!--连接池配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>-->

        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/demo"/>
        <property name="username" value="root"/>
        <property name="password" value="manager1"/>
    </bean>
    <!--
    创建sqlSessionFactory SqlSessionFactoryBean-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource"/>
        <!--配置类别名 实体类所在的包-->
        <property name="typeAliasesPackage" value="com.springmybatis.basic"></property>
        <!--配置映射文件的路径-->
        <property name="mapperLocations">
            <list>
                <value>
                    classpath:com.springmybatis.mapper.pz/*Mapper.xml
                </value>
            </list>
        </property>
    </bean>

    <!--
    创建DAO对象 MapperScannerConfigure-->
    <bean id="scannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
        <!--指定dto接口放的包-->
        <property name="basePackage" value="com.springmybatis.mapper"/>
    </bean>

</beans>

(3)按照配置文件配置的类别名,映射文件路径,指定dto对象的路径放对应的类或者xml文件

1. 实体
2. 表
3. DAO接⼝
4. Mapper⽂件配置

Spring 与MyBatis整合细节

Spring与MyBatis整合后,DTO不提交事务,但是数据能够插入数据库
1. Mybatis提供的连接池对象 ---> 创建Connection
Connection.setAutoCommit(false)⼿⼯的控制了事务 , 操作完成后,⼿⼯提交
2. Druid(C3P0 DBCP)作为连接池---> 创建Connection
Connection.setAutoCommit(true)true默认值 保持⾃动控制事务,⼀条sql⾃动提交
答案:因为Spring与Mybatis整合时,引⼊了外部连接池对象,保持⾃动的事务提交这个机制(Connection.setAutoCommit(true)),不需要⼿⼯进⾏事务的操作,也能进⾏事务的提交

Spring对事务的处理

(1)什么是事务

保证业务操作完整性的⼀种数据库机制
事务的4特点: A C I D
1. A 原⼦性
2. C ⼀致性
3. I 隔离性
4. D 持久性

(2)如何控制事务

JDBC:
Connection.setAutoCommit(false);
 Connection.commit();
 Connection.rollback();
MyBatis:
Mybatis⾃动开启事务
sqlSession(Connection).commit();
sqlSession(Connection).rollback();
---控制事务的底层 都是Connection对象完成的。

(3)Spring控制事务的开发

Spring是通过AOP的方式进行事务开发

原始对象

1. 原始对象 ---》 原始⽅法 ---》核⼼功能 (业务处理+DAO调⽤)
2. DAO作为Service的成员变量,依赖注⼊的⽅式进⾏赋值

额外功能

1.org.springframework.jdbc.datasource.DataSourceTransactionManager
2. 注⼊DataSource

1. MethodInterceptor
 public Object invoke(MethodInvocation invocation){
 try{
		Connection.setAutoCommit(false);
		 Object ret = invocation.proceed();
 		Connection.commit();
 	}catch(Exception e){
 	Connection.rollback();
  }
   return ret;
  }
2. @Aspect
 @Around

切入点

@Transactional
事务的额外功能加⼊给那些业务⽅法。
1. 类上:类中所有的⽅法都会加⼊事务
2. ⽅法上:这个⽅法会加⼊事务

组装切面

1. 切⼊点
2. 额外功能
<tx:annotation-driven transactionmanager=""/>

(4)开发

①添加依赖

//spring mybatis事务控制
// https://mvnrepository.com/artifact/org.springframework/spring-tx
compile group: 'org.springframework', name: 'spring-tx', version: '5.2.0.RELEASE'

②原始对象并在原始对象设值切入点

package com.springmybatis.service;

import com.springmybatis.basic.User;
import com.springmybatis.mapper.UserMapper;
import com.springmybatis.service.imp.UserServiceImp;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author PitterWang
 * @create 2020/6/15
 * @since 1.0.0
 */
@Transactional
public class UserService implements UserServiceImp {
    
    

   private UserMapper userMapper;

   public UserMapper getUserMapper() {
    
    
      return userMapper;
   }

   public void setUserMapper(UserMapper userMapper) {
    
    
      this.userMapper = userMapper;
   }

   @Override
   public void insertUser(User user) {
    
    
      userMapper.insertUser(user);
   }
}
<bean id="userService" class="com.springmybatis.service.UserService">
    <property name="userMapper" ref="userMapper"/>
</bean>

③额外功能

<bean id= "dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

④组装切面

    <tx:annotation-driven transaction-manager="dataSourceTransactionManager" proxy-target-class="true"/>

---proxy-target-class为true为用CGlib创建动态代理
---proxy-target-class为false为用JDK创建动态代理

Spring中的事务属性(Transaction Attribute)

(1)什么是事务属性

事务属性:描述事务特征的一系列值
1.隔离属性
2.传播属性
3.只读属性
4.超时属性
5.异常属性

事务属性的配置方法
@Transactional(isloation=,propagation=,readOnly=,timeout=,rollbackFor=,noRollbackFor=,)

(2)事务属性详解

隔离属性(ISOLATION)

    1.隔离属性:事务解决并发问题的特征
    2.事务并发产生的问题
    	脏读:一个事务,读取另一个事务没有提交的数据,会在本事务中产生不一致的问题
     解决方法:@Transactional(isolation=Isolation.READ_COMMITTED)
   
   
   不可重复读:一个事务中,多次读取相同的数据,但是读取结果不一样,会在本事务中产生数据不一致问题(一个事务中)
    解决方法:@Transactional(isolation=Isolation.REPEATABLE_READ)行锁
    
    
       幻读:⼀个事务中,多次对整表进⾏查询统计,但是结果不⼀样,会在本事务中产⽣数据不⼀致的问题
    解决方法:@Transactional(isolation=Isolation.SERIALIZABLE)表锁
    3.总结:
    并发安全:SERIALIZABLE>REPEATABLE_READ>READ_COMMITTED
    运行效率:READ_COMMITTED>REPEATABLE_READ>SERIALIZABLE
    4.数据库对于隔离属性的⽀持
    Oracle不⽀持REPEATABLE_READ值
    5.默认隔离属性
    ISOLATION_DEFAULT:会调⽤不同数据库所设置的默认隔离属性
		MySQL : REPEATABLE_READ
		Oracle: READ_COMMITTED
    

传播属性(PROPAGATION)

1.传播属性:他描述了事务解决嵌套问题的特征
2.参数的问题
⼤事务中融⼊了很多⼩的事务,他们彼此影响,最终就会导致外部⼤的事务,丧失了事务的原⼦性
3.传播属性的值及其⽤法
  见下表
4.默认传播属性
REQUIRED是传播属性的默认值
5.推荐传播属性的使⽤⽅式
增删改⽅法:直接使⽤默认值REQUIRED
查询操作:显示指定传播属性的值为SUPPORTS
传播属性的值 外部不存在事务 外部存在事务 ⽤法
REQUIRED 开启 新的 事务 融合到外部 事务中 @Transactional(propagation = Propagation.REQUIRED)
SUPPORTS 不开 启事 务 融合到外部 事务中 @Transactional(propagation = Propagation.SUPPORTS)
REQUIRES_NEW 开启 新的 事务 挂起外部事 务,创建新 的事务 @Transactional(propagation = Propagation.REQUIRES_NEW)
NOT_SUPPORTED 不开 启事 务 挂起外部事 务 @Transactional(propagation = Propagation.NOT_SUPPORTED)
NEVER 不开 启事 务 抛出异常 @Transactional(propagation = Propagation.NEVER)
MANDATORY 抛出 异常 融合到外部 事务中 @Transactional(propagation = Propagation.MANDATORY)

只读属性(readOnly)

针对于只进⾏查询操作的业务⽅法,可以加⼊只读属性,提供运⾏效率
默认值:false

超时属性(timeout)

指定了事务等待的最⻓时间
1. 为什么事务进⾏等待?
 当前事务访问数据时,有可能访问的数据被别的事务进⾏加锁的处理,那么此时本事务就必须进⾏等待。
2. 等待时间 秒
3. 如何应⽤
@Transactional(timeout=2)
4. 超时属性的默认值 -1
 最终由对应的数据库来指定

异常属性

Spring事务处理过程中
默认对于RuntimeException及其⼦类 采⽤的是回滚的策略
默认对于Exception及其⼦类 采⽤的是提交的策略
	rollbackFor ={java.lang.Exception,xxx,xxx}
	noRollbackFor ={java.lang.RuntimeException,xxx,xx}
@Transactional(rollbackFor ={java.lang.Exception.class},noRoll
backFor ={java.lang.RuntimeException.class})
建议:实战中使⽤RuntimeExceptin及其⼦类 使⽤事务异常属性的默认值

(3)基于标签的事务配置⽅式

原始方法

<bean id="userService" class="com.springmybatis.service.UserService">
    <property name="userMapper" ref="userMapper"/>
</bean>

扩展方法

<bean id= "dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

切入点

以前是注解方式,现在用配置文件

<tx:advice id = "txAdvice" transaction-manager="dataSourceTransactionManager">
    <tx:attributes>
        <tx:method name="insertUser" isolation="READ_COMMITTED" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

切面

<aop:config>
    <aop:pointcut id="pc" expression="execution(* com.springmybatis.service.UserService.insertUser(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>

猜你喜欢

转载自blog.csdn.net/weixin_35133235/article/details/106793442