背景
資料庫操作程序中,對于增刪改等操作,因為涉及到資料庫狀態的變更,為保證資料安全,需要進行事務管理;Spring事務管理有兩種方式,即宣告式事務管理和編程式事務管理;
配置
連接池配置:
# jdbc configuration
jdbc.url=jdbc\:mysql\://127.0.0.1\:3306/ssm?useUnicode\=true&characterEncoding\=utf8&characterSetResults\=utf8
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=123456
# 以下為 優化配置
jdbc.filters=stat
jdbc.maxActive=20
jdbc.initialSize=1
jdbc.maxWait=60000
jdbc.minIdle=10
jdbc.maxIdle=15
jdbc.timeBetweenEvictionRunsMillis=60000
jdbc.minEvictableIdleTimeMillis=300000
jdbc.validationQuery=SELECT 'x'
jdbc.testWhileIdle=true
jdbc.testOnBorrow=false
jdbc.testOnReturn=false
jdbc.maxOpenPreparedStatements=20
jdbc.removeAbandoned=true
jdbc.removeAbandonedTimeout=1800
jdbc.logAbandoned=true
<!-- 阿里 Druid 資料庫連接池 -->
<bean id="dataSource" init-method="init" destroy-method="close">
<!-- 資料庫基本資訊配置 -->
<property name="url" value="https://www.cnblogs.com/herokevin/p/${jdbc.url}" />
<property name="username" value="https://www.cnblogs.com/herokevin/p/${jdbc.username}" />
<property name="password" value="https://www.cnblogs.com/herokevin/p/${jdbc.password}" />
<property name="driverClassName" value="https://www.cnblogs.com/herokevin/p/${jdbc.driverClassName}" />
<property name="filters" value="https://www.cnblogs.com/herokevin/p/${jdbc.filters}" />
<!-- 最大并發連接數 -->
<property name="maxActive" value="https://www.cnblogs.com/herokevin/p/${jdbc.maxActive}" />
<!-- 初始化連接數量 -->
<property name="initialSize" value="https://www.cnblogs.com/herokevin/p/${jdbc.initialSize}" />
<!-- 配置獲取連接等待超時的時間 -->
<property name="maxWait" value="https://www.cnblogs.com/herokevin/p/${jdbc.maxWait}" />
<!-- 連接池最大空閑 -->
<property name="maxIdle" value="https://www.cnblogs.com/herokevin/p/${jdbc.maxIdle}" />
<!-- 最小空閑連接數 -->
<property name="minIdle" value="https://www.cnblogs.com/herokevin/p/${jdbc.minIdle}" />
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="https://www.cnblogs.com/herokevin/p/${jdbc.timeBetweenEvictionRunsMillis}" />
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="https://www.cnblogs.com/herokevin/p/${jdbc.minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="https://www.cnblogs.com/herokevin/p/${jdbc.validationQuery}" />
<property name="testWhileIdle" value="https://www.cnblogs.com/herokevin/p/${jdbc.testWhileIdle}" />
<property name="testOnBorrow" value="https://www.cnblogs.com/herokevin/p/${jdbc.testOnBorrow}" />
<property name="testOnReturn" value="https://www.cnblogs.com/herokevin/p/${jdbc.testOnReturn}" />
<property name="maxOpenPreparedStatements" value="https://www.cnblogs.com/herokevin/p/${jdbc.maxOpenPreparedStatements}" />
<!-- 打開removeAbandoned功能 -->
<property name="removeAbandoned" value="https://www.cnblogs.com/herokevin/p/${jdbc.removeAbandoned}" />
<!-- 1800秒,也就是30分鐘 -->
<property name="removeAbandonedTimeout" value="https://www.cnblogs.com/herokevin/p/${jdbc.removeAbandonedTimeout}" />
<!-- 關閉abanded連接時輸出錯誤日志 -->
<property name="logAbandoned" value="https://www.cnblogs.com/herokevin/p/${jdbc.logAbandoned}" />
</bean>
<!--事務管理器-->
<bean name="transactionManager" >
<property name="dataSource" ref="dataSource" />
</bean>
編程式事務管理
代碼演示:
package com.dongzz.ssm.modules.system.service;
import com.dongzz.ssm.SpringBaseJunit;
import com.dongzz.ssm.modules.system.entity.SysUser;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.sql.DataSource;
/**
* 編程式事務管理
*/
public class UserServiceTest extends SpringBaseJunit {
@Autowired
PlatformTransactionManager transactionManager;
@Autowired
DataSource dataSource;
JdbcTemplate jdbcTemplate;
@Test
public void transactionTest() {
String sql1 = "update book set `name` = '演算法導論(原書篇3版)' where id = 1";
String sql2 = "update book set `name` = 'Java編程思想(篇4版)' where id = 2";
// 設定事務隔離級別 傳播特性
DefaultTransactionDefinition dtd = new DefaultTransactionDefinition();
dtd.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
dtd.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 獲取事務狀態,spring根據傳播行為來開啟事務
TransactionStatus status = transactionManager.getTransaction(dtd);
jdbcTemplate = new JdbcTemplate(dataSource);
try {
jdbcTemplate.update(sql1);
jdbcTemplate.update(sql2);
transactionManager.commit(status); // 提交事務
} catch (Exception e) {
e.printStackTrace();
transactionManager.rollback(status); // 回滾事務
}
}
}
借助 spring 的 TransactionTemplate 工具類簡化事務管理編碼;
@Test
public void transactionTemplateTest() {
String sql1 = "update book set `name` = '演算法導論(原書篇3版)' where id = 1";
String sql2 = "update book set `name` = 'Java編程思想(篇4版)' where id = 2";
jdbcTemplate = new JdbcTemplate(dataSource);
TransactionTemplate template = new TransactionTemplate(transactionManager);
template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
template.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
jdbcTemplate.update(sql1);
jdbcTemplate.update(sql2);
}
});
}
宣告式事務管理
注解式
spring xml 添加如下配置:
<!-- 開啟 aop -->
<aop:aspectj-autoproxy proxy-target-/>
<!--事務管理器-->
<bean name="transactionManager" >
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 注解式事務管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
使用演示:
在需要開啟事務管理的類或方法上添加 @Transactional 注解即可;
package com.dongzz.ssm.modules.system.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import cn.hutool.core.util.StrUtil;
import com.dongzz.ssm.common.base.impl.BaseMybatisServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dongzz.ssm.common.plugin.datatables.PageTableHandler;
import com.dongzz.ssm.common.plugin.datatables.PageTableHandler.CountHandler;
import com.dongzz.ssm.common.plugin.datatables.PageTableHandler.ListHandler;
import com.dongzz.ssm.common.plugin.datatables.PageTableHandler.OrderHandler;
import com.dongzz.ssm.common.exception.ServiceException;
import com.dongzz.ssm.common.plugin.datatables.PageTableRequest;
import com.dongzz.ssm.common.plugin.datatables.PageTableResponse;
import com.dongzz.ssm.modules.system.dao.SysUserMapper;
import com.dongzz.ssm.modules.system.entity.SysUser;
import com.dongzz.ssm.modules.system.service.UserService;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserServiceImpl extends BaseMybatisServiceImpl<SysUser> implements UserService {
@Autowired
private SysUserMapper userMapper;
@Override
@Transactional
public void addUser(SysUser user) throws Exception {
SysUser u = userMapper.selectUserByUname(user.getUsername());
if (null != u) {
throw new ServiceException("用戶名已存在");
}
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
user.setStatus("1");
user.setIsDel("0");
userMapper.insertSelective(user);
}
}
AOP方式
spring xml 添加如下配置:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="add*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="save*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="delete*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.dongzz.*.service..*(..))" />
<aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
</aop:config>
上述配置將 txAdvice 切面中的通知方法動態的切入到名稱為 pc 的切入點運算式對應的位置,所有通配符匹配的方法均納入事務管理;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/419908.html
標籤:Java
