JDBC
事务ACID
原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。
一致性(consistency):在事务处理执行前后,数据库是一致的(两个账户要么都变,或者都不变)。
隔离性(isolcation):一个事务处理对另一个事务处理没有影响。
持续性(durability):事务处理的效果能够被永久保存下来 。
常用API
connection.setAutoCommit(false);关闭自动提交, 打开事务。
connection.commit();提交事务。
connection.rollback();回滚事务。
Savepoint sp = conn.setSavepoint();设置保存点
conn.rollback(sp);回滚到保存点
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);设置隔离级别, 可以通过Connection中的常量设置
隔离级别
在多线程并发访问数据库并且使用事务的时候, 可能会遇到脏读, 不可重复读, 幻读的情况, 需要设置隔离级别来避免
脏读: 读到的线程未提交的数据
不可重复读: 在一个事务中读取同一个记录两次, 获取数据不同
幻读: 在一个事务中, 读取到的记录数不同
隔离级别:
读未提交:Read Uncommitted;
读已提交:Read Committed;
可重复读:Repeatable Read;
可序列化:Serializable;
获取插入的ID
conn.prepareStatement(sql,Statement.return_generated_keys);
ResultSet rs = ps.getGeneratedKeys();
if (rs.next())
user.setId(rs.getInt(1));
MySQL的select last_insert_id()可以获取之前插入的记录的id, 但这只是MySQL才有的函数。
只有对自增长的列发生自增长的赋值后才会导致一个key的产生,并且用getGereratedKeys()返回。
批处理
由于建立连接,以及发送数据非常消耗性能,如果有大批SQL命令需要处理,最好使用批量处理。
ps =conn.prepareStatement("insert into user(name,password,email,birthday)values(?,?,?,?)");
for (User user : list) {
ps.setString(1, user.getName());
ps.setString(2, user.getPassword());
ps.setString(3, user.getEmail());
ps.setDate(4, newDate(user.getBirthday().getTime()));
ps.addBatch();
}
ps.executeBatch();
分页
通过ResultSet的滚动可以设置获取记录的位置, 但这样是从数据库中查询出所有数据, 然后再从结果中筛选结果,性能非常低.
MySQL提供了分页语法. 在查询语句后可使用LIMIT关键字完成分页功能, 例如:
select *from user limit 40,20
查询从user表中取出从第41条开始的20条记录. 第一个参数表示忽略前面多少个, 第二个参数代表取多少个.
可更新结果集、敏感结果集
conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet.TYPE_SCROLL_SENSITIVE
表示获得ResultSet之后是敏感的, 随数据库更新的. 但MySQL没有支持这项功能
ResultSet.CONCUR_UPDATABLE
表示获得ResultSet之后是可更新的, 例如:
rs.next();
rs.updateString("name","updateName");
rs.updateRow();
可以将当前行的name属性改为updateName.