spring 那种是可以的,一般指定用 @Transaction 指定一个service方法的事务,在service方法里面,只有出现异常(这个异常是可以指定的。),导致这个方法没有正常结束,这个就会数据库回滚。你只有把 Update 和insert写在一个方法里,然后把这个方法加上事务控制,那就可以了。这里面的实现逻辑大概是这样,首先spring获取连接, 我们在service方法里进行数据库的操作,然后方法结束, 如果正常结束,spring提交事务,释放连接。如果异常结束 ,spring 进行回滚,(这个回滚会把这个service方法内所有的修改操作回滚。)释放连接。 大体的流程是这样。至于这些逻辑在数据库层面是如何实现的,我也不知道。
成都创新互联公司是一家以成都网站建设公司、网页设计、品牌设计、软件运维、成都网站推广、小程序App开发等移动开发为一体互联网公司。已累计为成都玻璃贴膜等众行业中小客户提供优质的互联网建站和软件开发服务。
看你是什么事务,jdbc事务,还是分布式事务,还是容器事务
1,编程式事务管理(jdbc的事务是绑定在connection上的)
Connection conn = null;
try
{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@host:1521:SID","username","password");
conn.setAutoCommit(false); //取消自动提交
PreparedStatement ps = conn.prepareCall("update something");
ResultSet rs = ps.executeQuery();
conn点抗 mit(); //手动提交
}
catch (Exception e)
{
conn.rollback();
e.printStackTrace();
}
finally
{
conn.close();
}
2,声明式事务
先在工程的application.xml配置文件中添加如下代码,开启事务
!-- 声明式事务控制配置 --
tx:annotation-driven transaction-manager="txManager"/
bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
property name="datasource" ref="bassDataSource"/property
/bean
然后在你需要开启事务的接口前面添加注解
@Transactional(rollbackFor = IOException.class)
public void add(String name) throws IOException
{
System.out.println("可以再类里和方法里面添加事务注解0~0");
throw new IOException();
}
直接调用接口方法就好
分布式事务处理(mysql貌似在5.X之后才支持) 的话,
1.可以直接使用spring+atomikos框架进行管理
参考:
就不贴测试代码了,自己看着配置吧
2,使用JTA(Java Transaction API)进行分布式事务管理(测试代码如下)
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
//分布式事务处理
public class transferAccount
{
@SuppressWarnings("null")
public void testTransferAccount()
{
UserTransaction userts = null;
Connection connA = null;
PreparedStatement psA = null;
InitialContext context = null;
Connection connB = null;
PreparedStatement psB = null;
try
{
//获得事务管理对象
userts = (UserTransaction) context.lookup("java:comp/UserTransaction");
//获取两个数据库
connA = getDataSourceA().getConnection();
connB = getDataSourceB().getConnection();
//开启事务
userts.begin();
//sql语句
psA = connA.prepareStatement("我加1");
psB = connB.prepareStatement("我减1");
//执行sql
psA.executeUpdate();
psB.executeUpdate();
//事务提交
userts点抗 mit();
} catch (Exception e)
{
try
{
userts.rollback();
} catch (IllegalStateException | SecurityException
| SystemException e1)
{
e1.printStackTrace();
}
e.printStackTrace();
}
finally
{
try
{
psA.close();
psB.close();
connA.close();
connB.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
public DataSource getDataSourceA()
{
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setDatabaseName("mysql");
dataSource.setServerName("server");
dataSource.setPortNumber(1433);
dataSource.setUser("test");
dataSource.setPassword("test");
return dataSource;
}
public DataSource getDataSourceB()
{
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setDatabaseName("mysql");
dataSource.setServerName("server");
dataSource.setPortNumber(1435);
dataSource.setUser("test1");
dataSource.setPassword("test1");
return dataSource;
}
}
; 事务处理是企业应用需要解决的最主要的问题之一 J EE通过JTA提供了完整的事务管理能力 包括多个事务性资源的管理能力 但是大部分应用都是运行在单一的事务性资源之上(一个数据库) 他们并不需要全局性的事务服务 本地事务服务已然足够(比如JDBC事务管理) 本文并不讨论应该采用何种事务处理方式 主要目的是讨论如何更为优雅地设计事务服务 仅以JDBC事务处理为例 涉及到的DAO Factory Proxy Decorator等模式概念 请阅读相关资料 也许你听说过 事务处理应该做在service层 也许你也正这样做 但是否知道为什么这样做?为什么不放在DAO层做事务处理 显而易见的原因是业务层接口的每一个方法有时候都是一个业务用例(User Case) 它需要调用不同的DAO对象来完成一个业务方法 比如简单地以网上书店购书最后的确定定单为例 业务方法首先是调用BookDAO对象(一般是通过DAO工厂产生) BookDAO判断是否还有库存余量 取得该书的价格信息等 然后调用CustomerDAO从帐户扣除相应的费用以及记录信息 然后是其他服务(通知管理员等) 简化业务流程大概如此: 注意 我们的例子忽略了连接的处理 只要保证同一个线程内取的是相同的连接即可(可用ThreadLocal实现)
首先是业务接口 针对接口 而不是针对类编程
public interface BookStoreManager{ public boolean buyBook(String bookId int quantity)throws SystemException; 其他业务方法 }
接下来就是业务接口的实现类??业务对象
public class BookStoreManagerImpl implements BookStoreManager{ public boolean buyBook(String bookId)throws SystemException{ Connection conn=ConnectionManager getConnection();//获取数据库连接 boolean b=false; try{ conn setAutoCommit(false); //取消自动提交 BookDAO bookDAO=DAOFactory getBookDAO(); CustomerDAO customerDAO=DAOFactory getCustomerDAO(); //尝试从库存中取书 if(BookDAO reduceInventory(conn bookId quantity)){ BigDecimal price=BookDAO getPrice(bookId); //取价格 //从客户帐户中扣除price*quantity的费用 b= CustomerDAO reduceAccount(conn price multiply(new BigDecimal(quantity)); 其他业务方法 如通知管理员 生成定单等 conn mit(); //提交事务 conn setAutoCommit(true); } }catch(SQLException e){ conn rollback(); //出现异常 回滚事务 con setAutoCommit(true); e printStackTrace(); throws new SystemException(e); } return b; } }
然后是业务代表工厂
public final class ManagerFactory { public static BookStoreManager getBookStoreManager() { return new BookStoreManagerImpl(); } }
这样的设计非常适合于DAO中的简单活动 我们项目中的一个小系统也是采用这样的设计方案 但是它不适合于更大规模的应用 首先 你有没有闻到代码重复的 bad *** ell?每次都要设置AutoCommit为false 然后提交 出现异常回滚 包装异常抛到上层 写多了不烦才怪 那能不能消除呢?其次 业务代表对象现在知道它内部事务管理的所有的细节 这与我们设计业务代表对象的初衷不符 对于业务代表对象来说 了解一个与事务有关的业务约束是相当恰当的 但是让它负责来实现它们就不太恰当了 再次 你是否想过嵌套业务对象的场景?业务代表对象之间的互相调用 层层嵌套 此时你又如何处理呢?你要知道按我们现在的方式 每个业务方法都处于各自独立的事务上下文当中(Transaction Context) 互相调用形成了嵌套事务 此时你又该如何处理?也许办法就是重新写一遍 把不同的业务方法集中成一个巨无霸包装在一个事务上下文中
我们有更为优雅的设计来解决这类问题 如果我们把Transaction Context的控制交给一个被业务代表对象 DAO和其他Component所共知的外部对象 当业务代表对象的某个方法需要事务管理时 它提示此外部对象它希望开始一个事务 外部对象获取一个连接并且开始数据库事务 也就是将事务控制从service层抽离 当web层调用service层的某个业务代表对象时 返回的是一个经过Transaction Context外部对象包装(或者说代理)的业务对象 此代理对象将请求发送给原始业务代表对象 但是对其中的业务方法进行事务控制 那么 我们如何实现此效果呢?答案是JDK 引进的动态代理技术 动态代理技术只能代理接口 这也是为什么我们需要业务接口BookStoreManager的原因 首先 我们引入这个Transaction Context外部对象 它的代码其实很简单 如果不了解动态代理技术的请先阅读其他资料
lishixinzhi/Article/program/Java/gj/201311/27765
import java lang reflect InvocationHandler; import java lang reflect Method; import java lang reflect Proxy;
import java sql Connection;
import strutslet demo service SystemException;
public final class TransactionWrapper {
/** * 装饰原始的业务代表对象 返回一个与业务代表对象有相同接口的代理对象 */ public static Object decorate(Object delegate) { return Proxy newProxyInstance(delegate getClass() getClassLoader() delegate getClass() getInterfaces() new XAWrapperHandler( delegate)); } //动态代理技术 static final class XAWrapperHandler implements InvocationHandler { private final Object delegate;
XAWrapperHandler(Object delegate) { this delegate = delegate; } //简单起见 包装业务代表对象所有的业务方法 public Object invoke(Object proxy Method method Object[] args) throws Throwable { Object result = null; Connection con = ConnectionManager getConnection(); try { //开始一个事务 con setAutoCommit(false); //调用原始业务对象的业务方法 result = method invoke(delegate args); con mit(); //提交事务 con setAutoCommit(true); } catch (Throwable t) { //回滚 con rollback(); con setAutoCommit(true); throw new SystemException(t); }
return result; } } }
正如我们所见 此对象只不过把业务对象需要事务控制的业务方法中的事务控制部分抽取出来而已 请注意 业务代表对象内部调用自身的方法将不会开始新的事务 因为这些调用不会传给代理对象 如此 我们去除了代表重复的味道 此时 我们的业务代表对象修改成
public class BookStoreManagerImpl implements BookStoreManager { public boolean buyBook(String bookId)throws SystemException{ Connection conn=ConnectionManager getConnection();// 获取数据库连接 boolean b=false; try{ BookDAO bookDAO=DAOFactory getBookDAO(); CustomerDAO customerDAO=DAOFactory getCustomerDAO(); // 尝试从库存中取书 if(BookDAO reduceInventory(conn bookId quantity)){ BigDecimal price=BookDAO getPrice(bookId); // 取价格 // 从客户帐户中扣除price*quantity的费用 b= CustomerDAO reduceAccount(conn price multiply(new BigDecimal(quantity)); 其他业务方法 如通知管理员 生成定单等 } }catch(SQLException e){ throws new SystemException(e); } return b; } }
可以看到 此时的业务代表对象专注于实现业务逻辑 它不再关心事务控制细节 把它们全部委托给了外部对象 业务代表工厂也修改一下 让它返回两种类型的业务代表对象
public final class ManagerFactory { //返回一个被包装的对象 有事务控制能力 public static BookStoreManager getBookStoreManagerTrans() { return (BookStoreManager) TransactionWrapper decorate(new BookStoreManagerImpl()); } //原始版本 public static BookStoreManager getBookStoreManager() { return new BookStoreManagerImpl(); } }
我们在业务代表工厂上提供了两种不同的对象生成方法 一个用于创建被包装的对象 它会为每次方法调用创建一个新的事务 另外一个用于创建未被包装的版本 它用于加入到已有的事务(比如其他业务代表对象的业务方法) 解决了嵌套业务代表对象的问题 我们的设计还不够优雅 比如我们默认所有的业务代表对象的方法调用都将被包装在一个Transaction Context 可事实是很多方法也许并不需要与数据库打交道 如果我们能配置哪些方法需要事务声明 哪些不需要事务管理就更完美了 解决办法也很简单 一个XML配置文件来配置这些 调用时判断即可 说到这里 了解spring的大概都会意识到这不正是声明式事务控制吗?正是如此 事务控制就是AOP的一种服务 spring的声明式事务管理是通过AOP实现的 AOP的实现方式包括 动态代理技术 字节码生成技术(如CGLIB库) java代码生成(早期EJB采用) 修改类装载器以及源代码级别的代码混合织入(aspectj)等 我们这里就是利用了动态代理技术 只能对接口代理 对类的动态代理可以使用cglib库 这篇短文只是介绍下我对事务上下文模式以及声明式事务管理实现基本原理的理解 如有错误 请不吝赐教 谢谢 我的email:killme @gmail
lishixinzhi/Article/program/Java/gj/201311/27764