我猜数据库没有这条数据,number值是1。事务没理由能把primitive类型的数据都管起来吧?
解决方案 »
- Statement关闭,ResultSet无效?java.sql.SQLRecoverableException
- 面对众多RIA框架,我迷茫了!
- 200分(我只能发100分的帖子)求答案 每日构建
- JAVA 前途问题。。
- 页面传值问题?
- 急救!为何DAO为NULL啊
- tomcat严重问题
- 有没有什么办法,能让Web Service主动的向客户端发送些数据?
- 望请指导如何有效率的学习Java(写了几年Delphi,想转向Java)
- 推荐JBuilder8.0+weblogic7.0+oracle8i开发j2ee的书? 在线等
- 求j2ee下的web services的简单实例
- 关于“DES”加密的紧急求救
如果都catch块里撤消来实现的话,那
addTestTable("1");
addTestTable("1");
造成的一条脏数据,也可以在catch块里用delTestTable("1");来保持原子性;
但是用catch块来处理所有事务问题,肯定局限性太大。(EdRoman 精通EJB20关于事务章节有论述catch块来处理事务问题缺陷性)
有没有把握确定?
==================================================================================不错,
确切说是 提交/回滚 只认得通过事务管理器所能管理的资源,
普通的JAVA编码运算,是无法自动回滚的。
.......
UserTransaction ut = null;
ut=sessionContext.getUserTransaction();
int oldnumber;//再会滚前的数据
try
{
ut.begin();
oldnumber = number;
number++;
addTestTable("1");
addTestTable("1");
ut.commit();
}catch(Exception ex) {
ut.rollback();
number = oldnumber;
System.out.println(number);
}
......
其中:
1)afterBegin():容器在开始事务内第一个商业方法前调用该方法。
2)beforeCompletion():容器在将事务正式提交到数据库前调用该方法。
3)afterCompletion(bool flag):事务提交完成后调用该方法,其中参数flag为真表示提交成功,flag为假则表示事务回滚,此时你可能需要手编码从数据库同步提交前的数据。至于上面写的类似number++这样的普通java代码,
因为其只是普通的寄存器运算操作,不存在像持久化介质同步的问题,
因而这些用于事务上概念(如commit,rollback等)也不适用它。
那我怎么听说SESSION BEAN同时实现了SessionSynchronization接口,就可以做到那一点了呢。你在哪儿听的,瞎扯。你当事务处理是万能的,不支持事务处理的你用1000个 rollback 都不管用。不信就用用 access 来个事务,看看 rollback 有没有用,access 也是数据库啊,但是他不支持事务,记住事务处理只能使用在支持事务的机制上。变量的运算,java 虚拟机不支持这种事务(而且也没必要)必须自己去实现相应的操作,包括SessionSynchronization。
请看transferToSaving(double amount)方法里的
“checkingBalance -= amount;
savingBalance += amount;”
这两步涉及成员变量的业务运算,没有涉及任何数据库操作,所有的对这个两个成员变量的符值,回滚数据库操作都是实现在afterBegin(),afterCompletion(bool flag)里的,当事务回滚时,它回自动调用afterCompletion(bool flag)来撤消“checkingBalance -= amount;savingBalance += amount;”这两个运算。
---------------------------------------------------------------------------------
/*
*
* Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the proprietary information of Sun Microsystems, Inc.
* Use is subject to license terms.
*
*/import java.util.*;
import javax.ejb.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;public class BankBean implements SessionBean, SessionSynchronization { private String customerId;
private double checkingBalance;
private double savingBalance;
private SessionContext context;
private Connection con;
private String dbName = "java:comp/env/jdbc/BankDB"; public void transferToSaving(double amount) throws
InsufficientBalanceException { checkingBalance -= amount;
savingBalance += amount; try {
updateChecking(checkingBalance);
if (checkingBalance < 0.00) {
context.setRollbackOnly();
throw new InsufficientBalanceException();
}
updateSaving(savingBalance);
} catch (SQLException ex) {
throw new EJBException
("Transaction failed due to SQLException: "
+ ex.getMessage());
}
} public double getCheckingBalance() { return checkingBalance;
} public double getSavingBalance() { return savingBalance;
} public void ejbCreate(String id) throws CreateException { customerId = id; try {
makeConnection();
checkingBalance = selectChecking();
savingBalance = selectSaving();
} catch (Exception ex) {
throw new CreateException(ex.getMessage());
}
}
public void ejbRemove() { try {
con.close();
} catch (SQLException ex) {
throw new EJBException("ejbRemove SQLException: " + ex.getMessage());
}
} public void ejbActivate() { try {
makeConnection();
} catch (Exception ex) {
throw new EJBException("ejbActivate Exception: " + ex.getMessage());
}
} public void ejbPassivate() { try {
con.close();
} catch (SQLException ex) {
throw new EJBException("ejbPassivate Exception: " + ex.getMessage());
}
}
public void setSessionContext(SessionContext context) {
this.context = context;
} public void afterBegin() { System.out.println("afterBegin()");
try {
checkingBalance = selectChecking();
savingBalance = selectSaving();
} catch (SQLException ex) {
throw new EJBException("afterBegin Exception: " + ex.getMessage());
}
} public void beforeCompletion() { System.out.println("beforeCompletion()");
} public void afterCompletion(boolean committed) { System.out.println("afterCompletion: " + committed);
if (committed == false) {
try {
checkingBalance = selectChecking();
savingBalance = selectSaving();
} catch (SQLException ex) {
throw new EJBException("afterCompletion SQLException: " +
ex.getMessage());
}
}
} public BankBean() {}/************************** Database Routines **********************/ private void updateChecking(double amount) throws SQLException { String updateStatement =
"update checking set balance = ? " +
"where id = ?"; PreparedStatement prepStmt =
con.prepareStatement(updateStatement); prepStmt.setDouble(1, amount);
prepStmt.setString(2, customerId);
prepStmt.executeUpdate();
prepStmt.close();
} private void updateSaving(double amount) throws SQLException { String updateStatement =
"update saving set balance = ? " +
"where id = ?"; PreparedStatement prepStmt =
con.prepareStatement(updateStatement); prepStmt.setDouble(1, amount);
prepStmt.setString(2, customerId);
prepStmt.executeUpdate();
prepStmt.close();
} private double selectChecking() throws SQLException { String selectStatement =
"select balance " +
"from checking where id = ? ";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement); prepStmt.setString(1, customerId); ResultSet rs = prepStmt.executeQuery(); if (rs.next()) {
double result = rs.getDouble(1);
prepStmt.close();
return result;
}
else {
prepStmt.close();
throw new EJBException
("Row for id " + customerId + " not found.");
}
}
private double selectSaving() throws SQLException { String selectStatement =
"select balance " +
"from saving where id = ? ";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement); prepStmt.setString(1, customerId); ResultSet rs = prepStmt.executeQuery(); if (rs.next()) {
double result = rs.getDouble(1);
prepStmt.close();
return result;
}
else {
prepStmt.close();
throw new EJBException
("Row for id " + customerId + " not found.");
}
} private void makeConnection()
throws NamingException, SQLException { InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup(dbName);
con = ds.getConnection();
}} // BankBean
---------------------------------------------------------------------------
When the container rolls back a transaction, it always undoes the changes to data made by SQL calls within the transaction. However, only in entity beans will the container undo changes made to instance variables. (It does so by automatically invoking the entity bean's ejbLoad method, which loads the instance variables from the database.) When a rollback occurs, a session bean must explicitly reset any instance variables changed within the transaction. The easiest way to reset a session bean's instance variables is by implementing the SessionSynchronization interface.
if (committed == false) {
try {
checkingBalance = selectChecking();
savingBalance = selectSaving();
}
...
}
当事务提交失败时,committed的值肯定为假(容器负责为你设置);
此时,你需要做checkingBalance = selectChecking();
该操作实现上就是从数据库中重新读取一次数据并赋值给checkingBalance 。
因为事务提交失败了,所以此时数据库中的值并没有被改变,
checkingBalance = selectChecking()重新读取的效果正好相当于把checkingBalance恢复成事务提交前的值。至于selectChecking()方法具体内容,是需要你手工编码实现的。
“checkingBalance -= amount;
savingBalance += amount;”
这两步是没有数据库操作的,只是普通的JAVA运算,因为BEAN实现SessionSynchronization,所以这两步的数据也可以和updateChecking(checkingBalance)操作数据库的方法一样,得到事务的回滚。只不过它的具体实现是通过容器调用afterCompletion这个方法来完成的,也就是说,事务可以回滚成员变量的普通运算,但是你要实现SessionSynchronization这个接口。
---------------------------------------------------------------------------
...... public void afterBegin() {
number = 0;
} public void beforeCompletion() {
} public void afterCompletion(boolean committed) {
if (committed == false)
{
number--;
}
}......
[ if (committed == false)
{
number--;
}
}
] 这样的编码理解成事务回滚 我也没有办法:)number--;这一行是需要你手工编码的,容器不会自动为你生成它。
如果你不小心写成了number-=2,那数据完整性仍然会被破坏。
谢谢大家热情参与讨论,来者都有分。