Spring的声明式事务
声明式事务:使用AOP的形式横切进去,不会影响原有代码,保证可执行。
编程式事务:需要在代码中进行事务的管理,会影响原有代码,不能保证不会改出BUG。
1、注册事务
<!--注册事务-->
<bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--引入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
2、设置事务
<!--事务事务的执行方式-->
<tx:advice id="transactionName" transaction-manager="transaction">
<tx:attributes>
<!--设置所有方法都是开启事务-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
3、设置AOP,将事务织入切入点
<aop:config>
<!--设置切入点-->
<aop:pointcut id="point" expression="execution(* com.tx.mapper.*.*(..))"/>
<!--将事务织入切入点-->
<aop:advisor advice-ref="transactionName" pointcut-ref="point"/>
</aop:config>
Spring事务新特性(propagation) | propagation事务属性详解 |
---|---|
REQUIRED | 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常。 |
REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
NESTED | 支持当前事务,如果当前事务存在则执行一个嵌套事务,如果当前没有事务就新建一个事务 |
思考:
为什么需要事务?
- 如果不配置事务,可能导致提交的数据不一致(银行存取款)。
- 事务在项目开发中十分重要,和数据库相关的操作都十分重要,涉及到数据库的完整性和一致性的问题。
- 我们不在Spring配置中织入事务,继续要在代码中手动配置事务。
总结:涉及到数据库的操作必须要使用事务。
1.3、Transaction模板
需要配置
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
模板(先spring整合mybatis后)
<!--注册事务-->
<bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--引入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务事务的执行方式-->
<tx:advice id="transactionName" transaction-manager="transaction">
<tx:attributes>
<!--设置所有方法都是开启事务-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--设置切入点-->
<!--execution(*(表示返回类型) com.tx.mapper.*.*(..)):需要修改包名,(..表示所有参数)-->
<aop:pointcut id="point" expression="execution(* com.tx.mapper.*.*(..))"/>
<!--将事务织入切入点-->
<aop:advisor advice-ref="transactionName" pointcut-ref="point"/>
</aop:config>
</beans>
因为Spring自带的DriverManagerDataSource没有连接池所以使用dbcp连接池
<!--引入properties资源文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--destroy-method="close":Spring容器关闭时,数据源正常关闭,防止连接泄露-->
<bean id="dataSource" class="${dataSource}" destroy-method="close">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!--defaultReadOnly:设置是否只读,配置了读写分离可以设置为true-->
<property name="defaultReadOnly" value="false"/>
<!--启动数据库连接池初始创建的数据库连接数据(连接数据库默认开启五个连接)-->
<property name="initialSize" value="5"/>
<!--最多同时连接个数,超过进行等待,设置为负数则不闲置,以这个为准-->
<property name="maxOpenPreparedStatements" value="15"/>
<!--连接池空闲时间,最大连接数,超出释放,设置为负数则不闲置-->
<property name="maxIdle" value="10"/>
<!--连接池空闲时间,最小连接数,低于进行创建,设置为负数则不闲置-->
<property name="minIdle" value="2"/>
<!--最长等待时间,超过报错取消连接-->
<property name="maxWaitMillis" value="10000"/>
</bean>
properties资源
# dbcp连接池
dataSource=org.apache.commons.dbcp2.BasicDataSource
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/smbms?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username=tanxiang
password=abc123