我正在尝试处理Java中的多头处理。
我已经阅读了许多文章和问题(在StackOverflow上),但是找不到如何使用它的清晰示例。
我在HsqlDB数据库中有Unique_Numbers表。有2列:NUMBER和QTY。我的任务是检查数字是否存在,如果是,则增加数字的数量,如果不是,请插入此数字。
所以,我得到了什么。
这是我的数据库配置
private final ComboPooledDataSource dataSource;
public Database(String url, String userName, String password) throws PropertyVetoException {
dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("org.hsqldb.jdbcDriver");
dataSource.setJdbcUrl(url);
dataSource.setUser(userName);
dataSource.setPassword(password);
dataSource.setMaxPoolSize(10);
dataSource.setMaxStatements(180);
dataSource.setMinPoolSize(5);
dataSource.setAcquireIncrement(5);
}
这是我的逻辑:
public void insertRow(String number) throws SQLException {
int cnt = getCount(number);
if (cnt == 0) {
insert(number);
} else if (cnt > 0) {
update(number);
}
}
获取表中的数字
private int getCount(String number) {
int cnt = 0;
String sql = "select count(number) as cnt from \"PUBLIC\".UNIQUE_NUMBER where number='" + number + "'";
try {
Statement sta;
try (Connection connection = dataSource.getConnection()) {
sta = connection.createStatement();
ResultSet rs = sta.executeQuery(sql);
if (rs.next()) {
cnt = rs.getInt("cnt");
}
}
sta.close();
} catch (Exception e) {
LOGGER.error("error select cnt by number" + e.toString());
}
return cnt;
}
插入并更新
private boolean insert(String number) throws SQLException {
String sql = "insert into \"PUBLIC\".UNIQUE_NUMBER (number, qty) values(?, ?)";
try (Connection connection = dataSource.getConnection()) {
connection.setAutoCommit(false);
try (PreparedStatement ps = connection.prepareStatement(sql)) {
ps.setString(1, number);
ps.setInt(2, 0);
ps.addBatch();
ps.executeBatch();
try {
connection.commit();
} catch (Exception e) {
connection.rollback();
LOGGER.error(e.toString());
return false;
}
}
}
return true;
}
private boolean update(String number) throws SQLException {
String sql = "update \"PUBLIC\".UNIQUE_NUMBER set (qty) = (?) where number = ?";
int qty = selectQtyByNumber(number) + 1;
try (Connection connection = dataSource.getConnection()) {
connection.setAutoCommit(false);
try (PreparedStatement ps = connection.prepareStatement(sql)) {
ps.setInt(1, qty);
ps.setString(2, number);
ps.executeUpdate();
try {
connection.commit();
} catch (Exception e) {
connection.rollback();
LOGGER.error(e.toString());
return false;
}
}
}
return true;
}
如我所读,我必须使用池连接。每个线程建立一个连接很重要。启动应用程序时,出现约束异常或回滚异常:序列化失败。
我究竟做错了什么?
这是我的日志
[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.threads.InsertRowThread - exception while inserting numberintegrity constraint violation: check constraint; SYS_CT_10114 table: UNIQUE_NUMBER
[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.database.Database - error select cnt by number java.sql.SQLTransactionRollbackException: transaction rollback: serialization failure
[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.threads.InsertRowThread - exception while inserting numbertransaction rollback: serialization failure
[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.database.Database - error select cnt by number java.sql.SQLTransactionRollbackException: transactionrollback: serialization failure
非交易方式
先做增量
update UNIQUE_NUMBER set qty = qty + 1 where number = ?
检查是否更新了任何行,如果没有更新则插入数字
int rowsMatched = ps.executeUpdate();
if(rowsMatched == 0) {
try {
insert into UNIQUE_NUMBER (number, qty) values(?, 0)
} catch(Exception e) {
// the insert will fail if another thread has already
// inserted the same number. check if that's the case
// and if so, increment instead.
if(isCauseUniqueConstraint(e)) {
update UNIQUE_NUMBER set qty = qty + 1 where number = ?
} else {throw e;}
}
}
无交易处理(setAutoCommit(false)
,commit()
或rollback()
)reqired。
交易方式
如果您仍想以事务方式执行此操作,则需要在单个事务中执行所有步骤,例如@EJP建议:
connection.setAutoCommit(false);
// check if number exists
// increment if it does
// insert if it doesn't
// commit, rollback & repeat in case of error
connection.setAutoCommit(true);
如果此代码与其他代码共享连接池,则将auto commit设置回true(因为这是其他人期望连接处于的默认状态),或者明确表示池中的连接将始终处于事务模式。
在您的代码中,getCount
有时会在自动提交模式下获得一个连接(首次使用),有时会在事务性模式下获得一个连接(在insert
和/或之后重用update
)-这就是为什么您在中看到回滚异常的原因getCount
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句