Spring-与持久层整合
一、持久层整合
Spring框架为什么要与持久层技术进行整合
- JavaEE开发需要持久层进行数据库的访问操作
- JDBC Hibernate MyBatis进行持久开发过程存在大量的代码冗余
- Spring基于模板设计模式对于上述的持久层技术进行了封装
Spring可以与哪些持久层技术进行整合?
- JDBC
- JDBCTemplate
- Hibernate(JPA)
- HibernateTemplate
- MyBatis
- SqlSessionFactoryBean MapperScannerConfigure
二、Spring与MyBatis整合
Spring与MyBatis整合思路分析
Spring与MyBatis整合的开发步骤
- 配置文件(applicationContext.xml)进行相关的配置
<bean id="dataSource" class=""> <!--创建SqlSessionFactory--> <bean id="ssfb" class="SqlSessionFactoryBean"> <property name="dataSource" ref=""/> <property name="typeAliasesPackage"> <!--指定实体类所在的包 com.mysite.entity --> </property> <property name="mapperLocations"> <!--指定 配置文件(映射文件)的路径,com.mysite.mapper/*Mapper.xml--> </property> </bean> <!--DAO接口的实现类 SqlSession -> sqlSession.getMapper() ---- xxxDAO实现类对象 XxxDao -> xxxDao --> <bean id="scanner" class="MapperScannerConfigure"> <property name="sqlSessionFactoryBeanName" value="ssfb"/> <property name="basePackage" value=""> <!--指定DAO接口的包 com.mysite.dao/mapper--> </property> </bean>
经常根据需求的开发步骤
- 实体
- 表
- 创建DAO接⼝
- 实现Mapper⽂件
- 搭建开发环境(jar)
<!--Spring与MyBatis整合--> <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.6</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.13</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.22</version> </dependency>
- Spring文件的配置
<!--配置文件参数化--> <context:property-placeholder location="classpath:/jdbc.properties"/> <!--连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="name" value="${jdbc.username}"/> <property name="url" value="${jdbc.url}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--创建SqlSessionFactory SqlSessionFactoryBean--> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="com.mysite.entity"/> <property name="mapperLocations"> <list> <value>classpath:com.mysite.mapper/*Mapper.xml</value> </list> </property> </bean> <!--创建DAO对象 MapperScannerConfigure--> <bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/> <property name="basePackage" value="com.mysite.dao"/> </bean>
Spring与MyBatis整合细节
- 问题:Spring与MyBatis整合后,为什么Dao不提交事务,但是数据能够插入到数据库中?
Connection --> 事务
本质上控制连接对象(Connection) ---> 连接池(DataSource)
MyBatis提供的连接池对象 ---> 创建Connection
Connection.setAutoCommit(false) 手工控制事务
Druid(c3p0,DBCP)作为连接池 ---> 创建Connection
Connection.setAutoCommit(true) 自动控制事务
因为Spring与MyBatis整合时,引入了外部连接池对象,保持自动的事务提交这个机制(Connection.setAutoCommit(true))
三、Spring的事务处理
控制事务的底层 都是Connection对象完成的
Spring控制事务,通过AOP方式进行事务
原始对象
public void XxxUserServiceImpl(){
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();
throw new RuntimeException();
}
return ret;
}
//方式2. @Aspect @Around
切入点
@Transactional
事务的额外功能加入给哪些业务方法
1. 类上:类中所有的方法都会加入事务
2. 方法上:这个方法会加入事务
Spring控制事务的编码
- 搭建开发环境(jar)
<!--Spring整合事务--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.3.22</version> </dependency>
- 编码
<!--1. 原始对象--> <bean id="userService" class="com.mysite.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> <!--Spring整合MyBatis后,ref=userDao直接从SqlSessionFactory中创建的DAO对象中取--> </bean> <!--2. 额外功能 开启事务--> <!--通过 DataSourceTransactionManager 类获取dataSource连接池,从连接池中获取Connection连接对象,完成额外功能--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--3. 切入点--> @Transactional /*3. 切入点*/ public class UserServiceImpl implements UserService{ private UserDao userDao; } <!--4. 组装切入点和额外功能 自动扫描 切入点@Transactional--> <!--引入的 annotation-driven 结尾是tx的--> <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
- 细节
<tx:annotation-driven transaction-manager="dataSourceTransactionalManager" proxy-target-class="true"/> 进行动态代理底层实现的切换 默认 false JDK创建动态里 true Cglib
四、基于标签的事务配置方式
基于注解 @Transactional 的事务配置回顾 <!--1. 原始对象--> <bean id="userService" class="com.mysite.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> <!--Spring整合MyBatis后,ref=userDao直接从SqlSessionFactory中创建的DAO对象中取--> </bean> <!--2. 额外功能 开启事务--> <!--通过 DataSourceTransactionManager 类获取dataSource连接池,从连接池中获取Connection连接对象,完成额外功能--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--3. 切入点--> @Transactional /*3. 切入点*/ public class UserServiceImpl implements UserService{ private UserDao userDao; } <!--4. 组装切入点和额外功能 自动扫描 切入点@Transactional--> <!--引入的 annotation-driven 结尾是tx的--> <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
- 基于标签的事务配置
<!--1. 原始对象--> <bean id="userService" class="com.mysite.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> <!--Spring整合MyBatis后,ref=userDao直接从SqlSessionFactory中创建的DAO对象中取--> </bean> <!--2. 额外功能 事务配置--> <!--通过 DataSourceTransactionManager 类获取dataSource连接池,从连接池中获取Connection连接对象,完成额外功能--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--3. 事务属性--> <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager"> <tx:attributes> <tx:method name="register" isolation="DEFAULT",propagation="SUPPORTS"></tx:method> <tx:method name="login" ...></tx:method> 等效于 @Transactional(isolation=,propagation=) public void register(){ } </tx:attributes> </tx:advice> <!--4.通过AOP编程,组装 3和切面--> <aop:config> <aop:pointcut id="pc" expression="execution(* com.mysite.service.UserServiceImpl.register(..))"></aop:pointcut> <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"></aop:advisor> </aop:config>