IDEA spring整合mybatis入门(下)
继上一篇博客,添加事务管理
1.在maven工程中添加所需jar包
pom.xml
<!--使用AspectJ方式注解需要相应的包--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency>
2.修改applicationContext.xml配置文件
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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <!--加载配置文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置数据库信息--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 基本属性 url、user、password --> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- 配置监控统计拦截的filters --> <property name="filters" value="stat"/> <!-- 配置初始化大小、最小、最大 --> <property name="maxActive" value="20"/> <property name="initialSize" value="1"/> <property name="minIdle" value="1"/> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000"/> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000"/> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000"/> <property name="testWhileIdle" value="true"/> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/> <!-- 打开PSCache,并且指定每个连接上PSCache的大小 --> <property name="poolPreparedStatements" value="true"/> <property name="maxOpenPreparedStatements" value="20"/> <!-- 验证连接有效与否的SQL,不同的数据配置不同 --> <property name="validationQuery" value="select 1"/> </bean> <!-- ********************mapper配置&********************** --> <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 数据库连接池 --> <property name="dataSource" ref="dataSource"/> <!-- 加载mybatis的全局配置文件 --> <property name="configLocation" value="classpath:mybatisConfig.xml"/> <!-- 加载映射文件 --> <property name="mapperLocations" value="classpath:cn/spring/dao/StudentDao.xml"></property> </bean> <!--&&&&&&&&&&&&&&&&&&&两种方式选一种即可&&&&&&&&&&&&&&&&&&&&&&--> <!-- 配置mapper代理对象 --> <!--<bean id="studentDao" class="org.mybatis.spring.mapper.MapperFactoryBean">--> <!--<property name="mapperInterface" value="cn.spring.dao.StudentDao"/>--> <!--<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>--> <!--</bean>--> <!-- 扫描dao层接口 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.spring.dao"></property> <!--一定要是 value="sqlSessionFactory" --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"> </property> </bean> <!--&&&&&&&&&&&&&&&&&&&两种方式选一种即可&&&&&&&&&&&&&&&&&&&&&&--> <!--******************mapper配置结束***********************--> <!--*********************事务管理配置**********************--> <!-- 事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--配置事务管理的切入点--> <aop:config> <!--service层内的所有实现类的所有方法都添加事务--> <aop:pointcut id="serviceImpl" expression="execution(* cn.spring.service.impl.*.*(..))"/> <aop:advisor pointcut-ref="serviceImpl" advice-ref="txAdvice"/> </aop:config> <!--事务通知配置--> <tx:advice id="txAdvice" transaction-manager="txManager"><!--指定使用的事务管理器txManager--> <tx:attributes> <tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED" read-only="false" timeout="-1" rollback-for="java.lang.Exception"/> <tx:method name="delete*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="java.lang.Exception"/> <tx:method name="select*" propagation="REQUIRED" read-only="true"/> <tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="java.lang.Exception"/> </tx:attributes> </tx:advice> <!-- 事务注解驱动,标注@Transactional的类和方法将具有事务性 --> <!--<tx:annotation-driven transaction-manager="txManager" />--> <!--*********************事务管理配置结束**********************--> <!--基于classpath扫描方式--> <context:component-scan base-package="cn.spring"/> </beans>
3.如果选用@Transactional注解方法
业务层实现类
StudentServiceImpl.java
package cn.spring.service.impl; import cn.spring.bean.Student; import cn.spring.dao.StudentDao; import cn.spring.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service //当作用在类上时,该类所有的public方法都将具有该类型的事务属性。 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, readOnly = false, timeout = -1) public class StudentServiceImpl implements StudentService { @Autowired private StudentDao studentDao; //作用在方法上的标注将覆盖类级别的定义。 @Transactional(rollbackFor = Exception.class) public int deleteByPrimaryKey(Integer id) { return studentDao.deleteByPrimaryKey(id); } public int insert(Student record) { return studentDao.insert(record); } public int insertSelective(Student record) { return studentDao.insertSelective(record); } public int updateByPrimaryKeySelective(Student record) { return studentDao.updateByPrimaryKeySelective(record); } public int updateByPrimaryKey(Student record) { return studentDao.updateByPrimaryKey(record); } public Student selectByPrimaryKey(Integer id) { return studentDao.selectByPrimaryKey(id); } }
4.@Transactional属性以及用法
属性 | 类型 | 描述 |
---|---|---|
value | String | 可选的限定描述符,指定使用的事务管理器 |
propagation | enum: Propagation | 可选的事务传播行为设置 |
isolation | enum: Isolation | 可选的事务隔离级别设置 |
readOnly | boolean | 读写或只读事务,默认读写 |
timeout | int (in seconds granularity) | 事务超时时间设置 |
rollbackFor | Class对象数组,必须继承自Throwable | 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组,必须继承自Throwable | 导致事务回滚的异常类名字数组 |
noRollbackFor | Class对象数组,必须继承自Throwable | 不会导致事务回滚的异常类数组 |
noRollbackForClassName | 类名数组,必须继承自Throwable | 不会导致事务回滚的异常类名字数组 |
用法
@Transactional注解可以作用在接口,接口方法,类以及类方法上。当作用在类上时,该类所有的public方法都将具有该类型的事务属性。作用在方法上的标注将覆盖类级别的定义。
注意:在Spring中,建议不要在接口或者接口方法上使用该注解。因为Spring的代理方式分为基于接口的代理和基于类实现的代理,只有当Spring在使用基于类的代理时,注解才会生效。另外,@Transactional注解应该只被应用到public方法上,这是由Spring AOP本质决定的。应用在非public方法上,注解会被忽略,也不会抛出异常。
Spring AOP代理对象的生成有两种:JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。接口中不允许出现private、protected方法,同样子类实现中也不会出现private、protected等默认可见性方法。所以是无法被AOP所拦截,进而@Transactional注解不起效。
5.事务特性
5.1事务传播行为
事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
PROPAGATION_REQUIRED:当前方法必须在事务中运行,如果当前有事务环境就加入当前正在执行的事务环境,如果没有,则新建一个事务。此选项为默认值。
PROPAGATION_SUPPORTS:如果当前存在事务环境,该方法就加入事务中执行。如果当前没有事务,就以非事务的方式执行。
PROPAGATION_MANDATORY:当前方法必须在事务中运行,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:当前方法总是会为自己发起一个新的事务,如果当前方法已经运行在一个事务中,则原有事务被挂起,创建一个属于自己的事务,直到自身的事务commit结束,原有的事务才会恢复执行。
PROPAGATION_NOT_SUPPORTED:当前方法总是以非事务方式进行操作。如果当前存在事务,就把当前事务挂起,等该方法以非事务的状态运行完成,再继续原来的事务。
PROPAGATION_NEVER:当前方法总是以非事务方式进行操作。如果方法在事务范围内执行,容器则抛出异常。
PROPAGATION_NESTED:当前方法执行时,如果已经有一个事务存在,则以嵌套事务的方式运行在当前事务中。子事务可以单独的进行回滚提交操作,不会对父事务造成影响。但是子事务要受父事务的影响。
5.2事务隔离级别
事务隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
ISOLATION_DEFAULT:采用数据库默认隔离级别(以数据库为准,mysql:repeatable oracle:read committed)
ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
ISOLATION_READ_COMMITTED:大多数主流数据库的默认事务等级。保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了脏读。该级别使用与大多数系统。
ISOLATION_REPEATABLE_READ:保证一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据,也就是对同一字段在同一事务中多次读取的结果都是一致的。避免了脏读和不可重复读的情况,但是带来了更多的性能损耗。
ISOLATION_SERIALIZABLE:最严格的级别,事务串行执行,资源消耗最大。
5.3事务超时
事务超时指的是设置事务执行的最长时间,如果超过时间事务还没有执行完成便立即回滚该事务。在 TransactionDefinition 中以 int 的值来表示超时时间,单位为是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制
5.4事务只读属性
事务只读指的是操作数据库时,只进行读取操作,而不会做相应的修改。
只读事务并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。 但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。 因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可。
5.5事务回滚规则
指spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出那些异常时回滚事务,包括checked异常。
PS.RuntimeException + Error 和其子类都是属于 uncheck exception
Exception类中除了 RuntimeException之外的类 都是属于 check exception
5.6事务管理器
Spring本身并不管理事务,而是提供了许多的事务管理器,这些事务管理器都实现了org.springframework.transaction.PlatformTransactionManager接口,并且进行个性化的实现,达到事务管理的目的。
5.6.1DataSourceTransactionManager
DataSourceTransactionManager主要使用于由JDBC直接持久化数据的情况,例如Mybatis等。它通过调用java.sql.connection来管控事务,并且指定相应的DataSource。但是这并不意味着Connection具备事务功能,它仅仅是将commit,rollback等命令传递给数据库,由数据库本身的事务进行管理。并且像commit,rollback等事务功能和执行SQL的业务功能必须使用同一个Connection,才能真正实现事务管控的功能。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
5.6.2HibernateTransactionManager
HibernateTransactionManager主要使用于由Hibernate框架持久化数据的情况。它将事务功能和业务功能分隔开来,由Hibernate自身的Transaction来管理事务,使职责更为分明清晰。
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
5.6.3JpaTransactionManager
JpaTransactionManager主要使用于通过Java持久化API来持久化数据的情况。它需要装配一个JPA实体管理工厂(javax.persistence.EntityManagerFactory接口的任意实现),并且JpaTransactionManager将与由工厂所产生的JPA EntityManager合作来构建事务。
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
5.6.4JtaTransactionManager
JtaTransactionManager主要使用于包含多个数据源的分布式事务管控。
- Idea SpringMVC+Spring+MyBatis+Maven整合
- SSM框架整合 4000 (IntelliJ IDEA + maven + Spring + SpringMVC + MyBatis)
- SSM(Spring+SpringMVC+MyBatis)框架快速整合入门教程
- MyBatis入门程序之整合Spring
- 909422229_IDEA+maven+Spring+SpringMVC+Mybatis环境整合
- Maven+SpringMVC+Mybatis整合入门Demo
- SSM框架整合(IntelliJ IDEA + maven + Spring + SpringMVC + MyBatis)
- IDEA中解决spring整合mybatis后使用MapperScannerConfigurer扫描mapper包时“ Invalid bound statement (not found)”错误
- Spring MVC入门第2天--Spring、SpringMVC与MyBatis三大框架整合
- Spring boot入门五 spring mvc spring boot mybatis配置整合
- (转) Idea SpringMVC+Spring+MyBatis+Maven整合
- MyBatis入门(六)---mybatis与spring的整合
- SSM (IDEA) —— Spring,MyBatis和SpringMVC整合
- IDEA整合Spring+Springmvc+mybatis+maven详细教程
- Intellij-IDEA-maven+springMVC+mybatis整合DEMO
- IntelliJ IDEA 搭建基于Maven 的SSM(一)(spring,springMvc,Mybatis)框架整合
- springboot整合Mybatis(一)——入门
- MyBatis入门(六)---mybatis与spring的整合
- SSM (IDEA) —— Spring,MyBatis和SpringMVC整合配置文件
- 使用IDEA基于Maven搭建多模块聚合工程(springmvc+spring+mybatis整合)