如何在Java线程中将记录插入数据库?

我正在尝试处理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; } 

在我阅读时,我必须使用Pool Connection。 为每个线程提供一个连接很重要。 当我启动我的应用程序时,我得到了Rollback的约束exception或exception:序列化失败。

我究竟做错了什么?

这是我的日志

 [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() )。

交易方式

如果您仍希望以事务方式执行此操作,则需要在单个事务中执行所有步骤,例如@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); 

如果此代码与其他代码共享连接池(因为这是其他人希望连接处于的默认状态),则将自动提交设置为true,或者清楚地表明池中的连接将始终处于事务模式。

在您的代码中, getCount有时会在自动提交模式下获得连接(首次使用),有时会在事务模式下获得连接(在insert和/或update后重用) – 这就是您在getCount看到回滚exception的原因。