如何在 Java 线程中将记录插入数据库?
Posted
技术标签:
【中文标题】如何在 Java 线程中将记录插入数据库?【英文标题】:How to insert record to database in Java threads? 【发布时间】:2015-12-08 07:02:51 【问题描述】:我正在尝试处理 Java 中的多标题。
我已经阅读了很多文章和问题(在 *** 上),但没有找到任何明确的示例如何使用它。
我在 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;
当我阅读时,我必须使用池连接。为每个线程提供一个连接很重要。 当我启动我的应用程序时,我遇到约束异常或 Rollback 异常:序列化失败。
我做错了什么?
这是我的日志
[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
【问题讨论】:
你只是进入回滚,因为你已经有一个例外 - 它是什么?我猜你需要在提交之前创建/开始一个事务。 我只是猜测如果查询抛出了异常,那么事务必须回滚。我会在这里尝试交易和报告。 您的getCount
方法易受SQL 注入攻击。
您遇到了唯一约束违规,即您尝试插入的记录已经存在(或者主键已经存在)
你应该尽你所能在一条语句中执行整个事务。
【参考方案1】:
非交易方式
先做增量
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
中的异常。
【讨论】:
以上是关于如何在 Java 线程中将记录插入数据库?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Java 中将 ArrayList 数据类型插入 MySQL 数据库