一、解数据库事务
二、全面分析 Spring 的编程式事务管理及声明式事务管理
三、Spring事务管理自我理解的补充
1. 编程式事务管理
- 模板事务(TransactionTemplate)案例–步骤:获取模板对象;选择事务结果类型;业务数据操作处理。
- 平台事务管理器(PlatformTransactionManager)案例–步骤:获取事务管理器;获取事务属性对象;获取事务状态对象;创建JDBC模板对象;业务数据操作处理。
工具类TemplateUtils:
package com.mooc.utils;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
/**
* Spring数据库操作工具类
*/
public class TemplateUtils {
private final static String dbDriver = "com.mysql.jdbc.Driver" ;
private final static String dbUrl = "jdbc:mysql://127.0.0.1:3306/mytest?useSSL=false" ;
private final static String dbUser = "root";
private final static String dbPwd = "wenang++";
private static BasicDataSource dataSource ;
//静态初识:创建连接数据源
static {
//创建DBCP简单数据源并初始化相关数据源属性
//private void createSimpleDataSource(){
dataSource = new BasicDataSource() ;
dataSource.setDriverClassName(dbDriver);
dataSource.setUrl(dbUrl);
dataSource.setUsername(dbUser);
dataSource.setPassword(dbPwd);
//指定数据库连接池初始连接数
dataSource.setInitialSize(10);
//设定同时向数据库申请的最大连接数
dataSource.setMaxTotal(50);
//设置连接池中保持的最少连接数量
dataSource.setMinIdle(5);
//}
}
public static TransactionTemplate getTransactionTemplate() {
PlatformTransactionManager txManager = new DataSourceTransactionManager(
dataSource);
return new TransactionTemplate(txManager);
}
public static JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(dataSource);
}
public static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
return new NamedParameterJdbcTemplate(dataSource);
}
public static SimpleJdbcInsert getSimpleJdbcTemplate() {
return new SimpleJdbcInsert(dataSource);
}
/**
* //获取事务管理器:TransactionManager
* 根据需要,可以是如JDBC、Hibernate,这里定义JDBC事务管理其
* @return DataSourceTransactionManager
*/
public static DataSourceTransactionManager getDataSourceTransactionManager(){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
// 设置数据源:此事务数据源须和正式事务管理器的数据源一致
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
模板事务(TransactionTemplate)案例:
package com.mooc.springtransactions;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import com.mooc.utils.TemplateUtils;
public class TransManagerExample {
public static void main(String[] args) {
DataSourceTransactionManager dtm = TemplateUtils.getDataSourceTransactionManager();
// 创建事务管理器属性对象
DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定义事务属性
// 根据需要,设置事务管理器的相关属性
transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 设置传播行为属性
// 获得事务状态对象
TransactionStatus ts = dtm.getTransaction(transDef);
//基于当前事务管理器,获取操作数据库的JDBC模板对象
JdbcTemplate jt = new JdbcTemplate( dtm.getDataSource());
try{
jt.update("update books set price=112.5,name='炎黄传奇222' where isbn='128-166-890-China' ");
//其它数据操作如增删
dtm.commit(ts); //如果不commit,则更新无效果
} catch (Exception e) {
dtm.rollback(ts);
e.printStackTrace();
}
}
}
平台事务管理器(PlatformTransactionManager)案例:
// 1、编程式事务管理:事务管理器PlatformTransactionManager方式实现
public void updateBookByIsbn(Book book) {
//第一步:获取JDBC事务管理器
DataSourceTransactionManager dtm = TemplateUtils.getDataSourceTransactionManager();
// 第二步:创建事务管理器属性对象
DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定义事务属性
// 根据需要,设置事务管理器的相关属性
// 设置传播行为属性
transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
// 第三步:获得事务状态对象
TransactionStatus ts = dtm.getTransaction(transDef);
// 第四步:基于当前事务管理器,获取数据源,创建操作数据库的JDBC模板对象
JdbcTemplate jt = new JdbcTemplate(dtm.getDataSource());
try {//第五步:业务操作
jt.update("update books set price="+book.getPrice()+",name='"+book.getName()
+"' where isbn='"+book.getIsbn()+"' ");
// 其它数据操作如增删
//第六步:提交事务
dtm.commit(ts); // 如果不commit,则更新无效果
} catch (Exception e) {
dtm.rollback(ts);
e.printStackTrace();
}
}
2. 声明式事务管理
两种方式:tx拦截器;全注释(注解方式)。
POJO服务类:BookServiceImpl:
package com.mooc.service;
import com.mooc.beans.Book;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.transaction.annotation.Transactional;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* POJO服务类
*/
//使用全注释就使用@Transactional()
@Transactional()
public class BookServiceImpl extends JdbcDaoSupport implements BookService {
//r若不继承JdbcDaoSupport,则可按下面方式进行数据源的注入
private JdbcTemplate jdbcTemplate;
// public void setDataSource(DataSource dataSource) {
// this.jdbcTemplate = new JdbcTemplate((javax.sql.DataSource) dataSource);
// }
@Override
public void insertBook(Book book) {
String sql= "insert books(isbn,name,price,pubdate) values"
+"('"+book.getIsbn()+"','"+book.getName()+"',"+book.getPrice()+",'"+book.getPubdate()+"')" ;
this.getJdbcTemplate().update(sql);
}
@Override
public void updateBook(Book book) {
String sql = "update books set name='"+book.getName()+"' where isbn='"+book.getIsbn()+"' ";
this.getJdbcTemplate().update(sql);
}
@Override
public Book findBookByIsbn(String isbn) {
String sql = "select isbn,name,price,pubdate from books where isbn ='" + isbn + "'" ;
List<Book> books = this.getJdbcTemplate().query(sql,new RowMapper<Book>() {
public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
Book bk = new Book();
bk.setIsbn(rs.getString("isbn"));
bk.setName(rs.getString("name"));
bk.setPrice(rs.getFloat("price"));
bk.setPubdate(rs.getDate("pubdate"));
return bk;
}
});
return books!=null?books.get(0):null ;
}
}
- 继承JdbcDaoSupport 就需要再springContext.xml中配置dataSource(dataSource的配置暂且省略,下方会粘全代码):
<bean id="bookService" class="com.mooc.service.BookServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
- 若是采用全注释的方法就需要使用@Transactional(),并需要在springContext.xml声明。
<!-- 2、注释模式事务:启动使用注解实现声明式事务管理的支持 -->
<tx:annotation-driven transaction-manager="txManager" />
<!-- 要创建的事务服务对象 -->
<bean id="bookService" class="com.mooc.service.BookServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
- 若是采用tx拦截器
<!-- 1、通过事务通知的(AOP)模式实现事务管理
事务通知-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--事务语义定义... -->
<tx:attributes>
<!-- 以get开头的所有方法都为只读事务 -->
<tx:method name="find*" read-only="true"/>
<!-- 其它方法使用默认事务设置 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 确保上述事务通知对定义在BookService接口中的方法都起作用,
即对每个方法都开启一个对应的事务 -->
<aop:config>
<aop:pointcut id="bookServiceOperation" expression="execution(* com.mooc.service.BookService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="bookServiceOperation"/>
</aop:config>
springContext.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: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-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">
<!-- 引入数据库连接属性配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties" />
</bean>
<!-- 配置数据源 -->
<!-- #DBCP数据库连接池配置属性详细内容可参考官网描述:
#http://commons.apache.org/proper/commons-dbcp/configuration.html
-->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property>
</bean>
<!-- jdbc事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 2、注释模式事务:启动使用注解实现声明式事务管理的支持 -->
<tx:annotation-driven transaction-manager="txManager" />
<!-- 要创建的事务服务对象 -->
<bean id="bookService" class="com.mooc.service.BookServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 1、通过事务通知的(AOP)模式实现事务管理
事务通知-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--事务语义定义... -->
<tx:attributes>
<!-- 以get开头的所有方法都为只读事务 -->
<tx:method name="find*" read-only="true"/>
<!-- 其它方法使用默认事务设置 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 确保上述事务通知对定义在BookService接口中的方法都起作用,
即对每个方法都开启一个对应的事务 -->
<aop:config>
<aop:pointcut id="bookServiceOperation" expression="execution(* com.mooc.service.BookService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="bookServiceOperation"/>
</aop:config>
</beans>