您的位置:首页 > 编程语言 > Java开发

Spring事务管理器JDBC的实现

2016-12-09 20:48 936 查看
Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过Spring的事务接口来了解Spring实现事务的具体策略。 

Spring事务管理涉及的接口的联系如下:



Spring声明式事务管理器类:

               Jdbc技术:DataSourceTransactionManager

               Hibernate技术:HibernateTransactionManager

事务管理器

Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 

Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。此接口的内容如下:
Public interface PlatformTransactionManager()...{
// 由TransactionDefinition得到TransactionStatus对象
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交
Void commit(TransactionStatus status) throws TransactionException;
// 回滚
Void rollback(TransactionStatus status) throws TransactionException;
}


从这里可知具体的具体的事务管理机制对Spring来说是透明的,它并不关心那些,那些是对应各个平台需要关心的,所以Spring事务管理的一个优点就是为不同的事务API提供一致的编程模型,如JTA、JDBC、Hibernate、JPA。下面分别介绍各个平台框架实现事务管理的机制。

 JDBC事务

如果应用程序中直接使用JDBC来进行持久化,DataSourceTransactionManager会为你处理事务边界。为了使用DataSourceTransactionManager,你需要使用如下的XML将其装配到应用程序的上下文定义中:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>


实际上,DataSourceTransactionManager是通过调用java.sql.Connection来管理事务,而后者是通过DataSource获取到的。通过调用连接的commit()方法来提交事务,同样,事务失败则通过调用rollback()方法进行回滚。

注解方式声明事务

开启注解扫描

<!--事务管理器类-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启注解扫描-->
<context:component-scan base-package="com.juaner.spring.tx"/>

<!--注解方式实现事务-->
<tx:annotation-driven transaction-manager="txManager"/>


例子
<?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:mybatis="http://mybatis.org/schema/mybatis-spring"
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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd ">
<!-- 这一行是让他自动扫描注册spring bean -->
<context:component-scan base-package="spring.mybatis.transaction"> </context:component-scan>
<tx:annotation-driven transaction-manager="txManager"/>
<!-- 这一行是基于注解实现事务管理器   下面这个是具体的jdbc的事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="123" /><!-- 其实这些参数也可以直接写值,不用.properties文件也行 -->
</bean>
</beans>
简单JAV类(POJO)

package spring.mybatis.transaction;

public class Account {
private String user;
private int balance;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
DAO具体实现类。此时并没有合并MyBatis。所以不是借口,还是类。但需要注意的是。这里的映射关系实现是通过RowMapper<Account>()这个匿名类实现的。
package spring.mybatis.transaction;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class AccountDao {
private JdbcTemplate jdbcTemplate;//此处是同过Spring JDBC 连接数据库。不是mybatis。

@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public void resetMoney() {
jdbcTemplate.update("update account set balance=1000");
}

public List<Account> accountList() {
return this.jdbcTemplate.query("select * from account", new RowMapper<Account>() { // 消除警告的是靠
// new RowMapper<Account>的泛型
//里RowMapper可以将数据中的每一行数据封装成用户定义的类。当有了mybatis后就不用这样了。mybatis会将查询结果映射成就扣对象
//sping中的RowMapper可以将数据中的每一行数据封装成用户定义的类。
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
// TODO Auto-generated method stub
Account account = new Account();

account.setUser(rs.getString("user"));
account.setBalance(rs.getInt("balance"));

return account;
}
});
}

// 下面这个就是事物
@Transactional(propagation=Propagation.REQUIRED)
public void transforMoney(String source, String target, double count) {

this.jdbcTemplate.update("update account set balance=balance-? where user=?", count, source);
// 下面故意加入错误,使事物中断
throwException();
this.jdbcTemplate.update("update account set balance=balance+? where user=?", count, target);
}

private void throwException() {
throw new RuntimeException("ERROR");
}
}


实现类
package spring.mybatis.transaction;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import spring.jdbc.JdbcTemplateDao;

public class TestData {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("springmybatistransaction.xml");

AccountDao dao=ctx.getBean("accountDao", AccountDao.class);
dao.resetMoney();

/*
* 这里给dao.transforMoney加try catch 是为了让即使出错也能打印出来余额。。?
*/
try{
dao.transforMoney(" LiLei", " HaiMeiMei", 521);
}catch(Exception e){
System.out.println(e.getMessage());
}
List<Account> accountList =dao.accountList();
for(Account account:accountList){

System.out.println(account.getUser()+account.getBalance());
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: