- 一、事务-掌握
JDBC当你执行增删改语句时,事务会自动开启。每插入一条语句,开启一个事务,不能达到数据一致
JDBC中如何手工控制事务?
什么时候使用自动事务?什么时候使用手工事务?
- 当你一次只操作一张表时,且没有批处理时则可以使用自动事务;
- 如果往同一张表插入多条记录,这多条记录有特别要求说要么同时成功,要么同时失败时就要使用手工事务;如果在同一个方法内部使用JDBC语句操作了多张表,必须使用手工事务(这样才能达到统一控制的目的)
conn.setAutoCommit(false);//JDBC设置不自动提交事务,此时事务打开了,可手工控制事务
事务(ACID)
- 原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。
- 一致性(consistency):在事务处理执行前后,数据库是一致的(数据库数据完整性约束)。
- 隔离性(isolcation):一个事务处理对另一个事务处理的影响。
- 持续性(durability):事务处理的效果能够被永久保存下来 。
- 在JDBC中,事务默认是自动提交的
- 通过Connection的setAutoCommit()方法来设置事务的提交属性。如:connection.setAutoCommit(false);//打开事务。
- 通过Connection的getAutoCommit()方法来获得当前事务的提交方式
- 通过Connection的commit()方法来提交事务
- 通过Connection的rollback()方法来回滚事务
事务(SavePoint-创建保存点)-了解
当只想撤销事务中的部分操作时可使用SavePoint
//创建保存点
SavePoint sp = connection.setSavepoint();
connection.rollerbak(sp);
connection.commit();
注:Oracle数据库的classes12.jar驱动程序对保存点的支持存在缺陷,所以无法使用,如果要在Oracle中使用保存点功能,需要使用odjbc1.4.jar,MySQL的数据库驱动对保存点的支持较为完善,可以使用。
事务(JTA)
JDBC是不能够进行跨数据库事务管理的
跨越多个数据源的事务,使用JTA容器(应用服务器)实现事务。
分成两阶段提交。
javax.transaction.UserTransaction tx = (UserTransaction)ctx.lookup(“jndiName");
tx.begin();
//connection1 connection2 (可能来自不同的数据库)…
tx.commit();
//tx.rollback();
隔离级别多线程并发读取数据时的正确性
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
√ :可能出现,X:不会出现
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(Read uncommitted) | √ | √ | √ |
读已提交(Read committed) | x | √ | √ |
可重复读(Repeatable read) | x | x | √ |
可串行化(Serializable ) | x | x | x |
一般不会通过Java应用程序去修改数据库的隔离级别,一般都是使用数据库默认的隔离级别(读已提交),如果将数据库的隔离级别设置过高,会导致数据库并发性能的下降。
- 脏读(dirty reads)
一个事务读取了另一个未提交的并行事务写的数据。
- 不可重复读(non-repeatable reads)
一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。
- 幻读(phantom read)
一个事务重新执行一个查询,返回一套符合查询条件的记录, 发现这些记录因为其他最近提交的事务而发生了改变。
使用CallableStatement调用存储过程
当不直接使用SQL语句,而是调用数据库中的Store Procedure(存储过程)时,要用到Callable Statement
CallabelStatement从PreparedStatement继承
CallableStatement(从PreperedStatement扩展来)
cs=connection.prepareCall(“{call psname(?,?,?)}”);
cs.registerOutParameter(index,Types.INTEGER);
cs.setXXX(i, xxxx);
cs.executeUpdate();
int id=cs.getInt(index);
其他的几个API
PreparedStatement.getGeneratedKeys()
PreparedStatement ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
rs.getInt(1);
批处理,可以大幅度提升大量增、删、改的速度。
PreparedStatement.addBatch();
PreparedStatement.executeBatch();
- 二、批处理-掌握
可以将一些相关的数据库操作放到同一个Batch中:
- 使用Statement的addBatch()方法,将一系列的操作放到同一个Batch中
- 利用Statement的executeBatch()方法,来成批执行放到同一个Batch中的操作
- 可以将Batch操作和事务结合起来使用。将放到 Batch中的操作当成一个事务
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.addBatch(“insert into table1…”);
stmt.addBatch(“insert into table2…”);
stmt.addBatch(“update table3…”);
…
stmt.executeBatch();
conn.commit()
…