事务
MySQL:每一条语句都属于独立事务,默认自动管理提交的。
如果需要把多条语句当成一个整体,那么就需要把多条语句放在一个事务里面
开启事务:start transaction
提交事务:commit;
回滚事务:rollback
JDBC控制事务语句
Connection.setAutoCommit(false); start transaction
Connection.rollback(); rollback
Connection.commit(); commit
例子
模拟一个转账的功能,用事务来控制
public static void main(String[] args) {
Connection connection = null;
PreparedStatement statement1 = null;
PreparedStatement statement2 = null;
try {
connection = DBUtil.getConnection();
//开启事务
connection.setAutoCommit(false);
String sql1 = "UPDATE bank SET money=money-200 WHERE id=1;";
statement1 = connection.prepareStatement(sql1);
statement1.executeUpdate();
// System.out.println(10/0);
String sql2 = "UPDATE bank SET money=money+200 WHERE id=2;";
statement2 = connection.prepareStatement(sql2);
statement2.executeUpdate();
//提交事务
connection.commit();
} catch (Exception e) {
//回滚事务
if(connection != null){
try {
connection.rollback();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
} finally {
DBUtil.close(null,statement2,null);
DBUtil.close(connection,statement1,null);
}
}
}
事务的特点
事务的特性:ACID
原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持久性( Durability )
原子性:事务是数据库的逻辑工作单位,事务中包含的各操作要么都完成,要么都不完成
一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
隔离性:一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性:指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
事务的隔离级别:
属于事务的。都已开启了事务为前提。
不考虑事务的隔离级别,会出现以下的情况
- 脏读:一个线程中的事务读到了另外一个线程中未提交的数据。
- 不可重复读:一个线程中的事务读到了另外一个线程中已经提交的update的数据。
- 虚读:一个线程中的事务读到了另外一个线程中已经提交的insert的数据。
要想避免以上现象,通过更改事务的隔离级别来避免:
- READ UNCOMMITTED 脏读、不可重复读、虚读有可能发生。
- READ COMMITTED 避免脏读的发生,不可重复读、虚读有可能发生。
- REPEATABLE READ 避免脏读、不可重复读的发生,虚读有可能发生。
- SERIALIZABLE 避免脏读、不可重复读、虚读的发生。
set transaction isolation level READ COMMITTED;
级别依次升高,效率依次降低。
MySQL:默认REPEATABLE READ
ORACLE:默认READ COMMITTED
MySQL:
SELECT @@SESSION.transaction_isolation;//查看当前的隔离级别
set transaction isolation level 级别;// 设置当前的事务隔离级别
练习:read uncommitted;
时间 | T1 | T2 | 说明 |
t1 | start transaction | ||
t2 | select * from account where id=1; 1000 | ||
t3 | start transaction | ||
t4 | update account set balance=balance+100 where id=1; | ||
t5 | select * from account where id=1; 1100 | 读到了另外一个线程中未提交的数据:脏读 | |
t6 | commit; | ||
t7 | select * from account where id=1; 1100 | 读到了另外一个线程中提交的update数据:不可重复读 | |
t8 | select count(*) from account; 2 | ||
t9 | insert into account values(3,'wangwu',1000); | ||
t10 | select count(*) from account; 3 | 读到了另外一个线程中提交的insert数据:虚读(幻读) | |
t11 | commit; | ||
JDBC设置隔离级别
批处理 --- 批量处理sql语句
1.多条不一样的sql语句
public static void main(String[] args) throws SQLException {
Connection connection = DBUtil.getConnection();
Statement statement = connection.createStatement();
//将多条sql命令添加到Batch包中
String sql1 = "insert into student(name,course_id,class_id,age) values('ccc',1,3,20)";
String sql2 = "update student set age=19 where id=2";
statement.addBatch(sql1);
statement.addBatch(sql2);
//发送Batch包
statement.executeBatch();
DBUtil.close(connection,statement,null);
}
}
2.多条SQL命令一样但参数不一样
public static void main(String[] args) throws SQLException {
Connection connection = DBUtil.getConnection();
String sql = "insert into student(name,course_id,class_id,age) values(?,1,3,20)";
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 1; i <= 20; i++) {
statement.setString(1,"小黑"+i);
statement.addBatch();
}
statement.executeBatch();
DBUtil.close(connection,statement,null);
}
}
多条SQL命令一样但参数不一样- 大量数据
public static void main(String[] args) throws SQLException {
Connection connection = DBUtil.getConnection();
connection.setAutoCommit(false);
String sql = "insert into student(name,course_id,class_id,age) values(?,1,3,20)";
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 1; i <= 20000; i++) {
statement.setString(1,"小红"+i);
statement.addBatch();
if(i%1000 == 0){
statement.executeBatch();
statement.clearBatch();//清空Batch包中的数据
}
}
connection.commit();
DBUtil.close(connection,statement,null);
}
}
CBLob
JDBC可以向数据库存储二进制数据或长文本数据
* BLob - Binary(二进制)Lob - 存储二进制数据 - 注意:数据库字段类型 - BLOB/LONGBLOB
* CLob - Character(字符)Lob - 存储长文本数据 - 注意:数据库字段类型 - TEXT/LONGTEXT
blob
public void test01() throws SQLException, FileNotFoundException {
//将图片插入到数据库中
Connection connection = DBUtil.getConnection();
String sql = "insert into cblob(b_lob) values (?)";
PreparedStatement statement = connection.prepareStatement(sql);
InputStream in = new FileInputStream("葵司.jpg");
statement.setBinaryStream(1,in);
statement.executeUpdate();
DBUtil.close(connection,statement,null);
}
@Test
public void test02() throws SQLException, IOException {
//将数据库中的图片读取到本地
Connection connection = DBUtil.getConnection();
String sql = "select * from cblob where id=1";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
if(resultSet.next()){
InputStream in = resultSet.getBinaryStream("b_lob");
FileOutputStream out = new FileOutputStream("copyImg.jpg");
byte[] bs = new byte[1024];
int len;
while((len = in.read(bs)) != -1){
out.write(bs,0,len);
}
in.close();
out.close();
DBUtil.close(connection,statement,resultSet);
}
}
}
clob
public void test01() throws SQLException, FileNotFoundException {
//将长文本数据插入到数据库中
Connection connection = DBUtil.getConnection();
String sql = "insert into cblob(c_lob) values (?)";
PreparedStatement statement = connection.prepareStatement(sql);
FileReader reader = new FileReader("小说.txt");
statement.setCharacterStream(1,reader);
statement.executeUpdate();
DBUtil.close(connection,statement,null);
}
@Test
public void test02() throws SQLException, IOException {
//将数据库中的长文本数据读取到本地
Connection connection = DBUtil.getConnection();
String sql = "select * from cblob where id=2";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
if(resultSet.next()){
Reader reader = resultSet.getCharacterStream("c_lob");
FileWriter writer = new FileWriter("copyText.txt");
char[] cs = new char[1024];
int len;
while((len = reader.read(cs)) != -1){
writer.write(cs,0,len);
}
reader.close();
writer.close();
DBUtil.close(connection,statement,resultSet);
}
}
}