6.1 理解事务管理
任何处理数据的系统都必须保证数据的完整性、事务为与数据相关的操作定义了一个边界,并将他们组合在一起,以便这些操作的最终结果不会使底层数据出于不一致的状态。
具有的特性:原子性 事务在数据上有多个操作而且每个操作都必须成功,否则进行回滚。一致性 一个活动事务结束后底层事务必须处于一致状态。 隔离性 定义了保护未提交的数据免受其他并发事务的影响。 持久性 接收到一个成功的信息提交时,系统就具有了持久性。
package com.tzg.ch601;
public interface AccountServer {
public void transferMoney(long sourceAccountId,long targetAccountId,double amount);
}
package com.tzg.ch601;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Driver;
public class AccountServerJdbcTxImpl implements AccountServer {
@Override
public void transferMoney(long sourceAccountId, long targetAccountId,
double amount) {
Connection connection = null;
System.out.println("开始。。。。。。。。。");
try {
System.out.println("开启事务。。。。。。。。。");
//加载驱动
DriverManager.registerDriver(new Driver());
//取得连接DriverManager.getConnection();
connection=(Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/num","root","123456");
//调用connection.setAutoCommit(false)来标记使用JDBC API定义的事务边界起点,来引起一个新的事务的开始。
connection.setAutoCommit(false);
//取得接口的声明
Statement statement = connection.createStatement();
statement.executeUpdate("update account set balance = balance - "+amount+ "where id= "+sourceAccountId);
statement.executeUpdate("update account set balance = balance + "+amount+ "where id= "+targetAccountId);
//事务划分成功终止
connection.commit();
} catch (SQLException e) {
try {
//处理的数据中如果发现了错误,用connection.rollback()回滚告诉jdbc抛弃目前为止所做的任何更改。
System.out.println("发现错误。。。。。。。");
connection.rollback();
} catch (SQLException e1) {
System.out.println("数据库操作失败");
}
throw new RuntimeException(e);
}
}
}
package com.tzg.ch601;
public class Main {
public static void main(String[] args) {
AccountServer accountServer=new AccountServerJdbcTxImpl();
accountServer.transferMoney(100L, 101L, 6.0d);
System.out.println("运行结束。。。。。。。。。。。");
}
}
项目结构:
6.2 spring 的事务抽象模型
Spring的事务抽象模型基于PlatformTransactionManager接口并且存在不同的具体实现,而且每种实现都与一个特定的访问技术相对应,个人要确定好是使用的那一个技术。默认的情况下为transactionManager
6.2.1 本地事务与全局事务
本地应用程序使用单一的数据库,切事务仅控制在该单一的数据库上执行的DML操作。全局事务则意味着分布式事务管理。在一个事务中可能涉及到多个数据库。
6.2.2 PlatformTransactionManager 实现
6.2.3Spring 的抽象事务模型的优点
能够在相同的应用平台中使用不同的数据访问技术、可以同时使用声明式和编程式访问模型。本地事务和全局事务很容易转换。
6.3 使用Spring进行声明式事务管理
事务管理是一个横切关注点,而横切关注点最好使用面向方面编程来处理。
实例 spring中启动声明事务管理
package com.tzg.ch602;
public interface AccountServer {
public void transferMoney(long sourceAccountId,long targetAccountId,double amount);
}
package com.tzg.ch602;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.annotation.Transactional;
import com.mysql.jdbc.Connection;
public class AccountServerImpWithSpring implements AccountServer {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Transactional
public void transferMoney(long sourceAccountId, long targetAccountId,
double amount) {
Connection connection=(Connection) DataSourceUtils.getConnection(dataSource);
try {
Statement statement =connection.createStatement();
statement.executeUpdate("update account set balance = balance - "+amount+ "where id= "+sourceAccountId);
statement.executeUpdate("update account set balance = balance + "+amount+ "where id= "+targetAccountId);
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new RuntimeException();
}finally{
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
}
package com.tzg.ch602;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
//激活了基于注解的事务管理
@EnableTransactionManagement
public class Ch6Configuration {
@Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/num");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(){
DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager;
}
@Bean
public AccountServer accountServer(){
AccountServerImpWithSpring bean=new AccountServerImpWithSpring();
bean.setDataSource(dataSource());
return bean;
}
}
package com.tzg.ch602;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
private static AnnotationConfigApplicationContext configApplicationContext;
public static void main(String[] args) {
configApplicationContext = new AnnotationConfigApplicationContext(Ch6Configuration.class);
AccountServer accountServer=configApplicationContext.getBean(AccountServer.class);
accountServer.transferMoney(100L, 101L, 2.0d);
}
}
6.3.1 将服务层与数据访问层进行分离
package com.tzg.ch402;
import org.springframework.transaction.annotation.Transactional;
public class AccountServiceImpl implements AccountServer {
private AccountDao accountdao;
public void setAccountdao(AccountDao accountdao) {
this.accountdao = accountdao;
}
@Transactional /*(没有这个注解的是基于xml的)*/
//标记服务类的transferMoney(..)方法,并实现该方法。注意其中要导入包aspectj.weaver.jar 包
public void transferMoney(long sourceAccountId, long targetAccountId,
double amount) {
Account sourceAccount=accountdao.find(sourceAccountId);
Account targetAccount=accountdao.find(targetAccountId);
sourceAccount.setBalance(sourceAccount.getBalance()-amount);
targetAccount.setBalance(targetAccount.getBalance()+amount);
accountdao.update(sourceAccount);
accountdao.update(targetAccount);
}
}
package com.tzg.ch402;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
//激活了基于注解的事务管理
@EnableTransactionManagement
@ImportResource("classpath:/beans-tx.xml")
@Import(Ch4Configuration.class)
public class Ch6Configuration {
@Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/num");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(){
DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager;
}
@Bean
@Autowired//可以在创建方法期间将accountDao Bean作为一个方法输入参数传入到方法中。
public AccountServer accountServer(AccountDao accountDao){
AccountServiceImpl bean=new AccountServiceImpl();
bean.setAccountdao(accountDao);
return bean;
}
/* @Bean
public AccountServer accountServer(){
AccountServerImpWithSpring bean=new AccountServerImpWithSpring();
bean.setDataSource(dataSource());
return bean;
}
*/
}
注意其中的依赖包
6.3.5 使用<tx:advice>进行声明事务管理
添加依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
创建beans-tx.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="bean(accountService)" />
</aop:config>
</beans>
删除出AccountServiceImpl类中的@Transaction注解。添加
@Configuration
//激活了基于注解的事务管理
@ImportResource("classpath:/beans-tx.xml")
@Import(Ch4Configuration.class)
6.4 使用Spring进行编程式事务管理