JDBC高级操作和事务处理(mysql)

JDBC批处理

  • piliang处理允许将相关的SQL语句分组到批处理中,并通过对数据库的一次调用提交它们
  • 当需要一次向数据库发送多个SQL语句时,可以减少连接数据库的开销,从而提高性能
  • 在jdbc的URL中添加rewriteBatchedStatements=true参数,可以提高批处理执行效率
Statement批处理
  • 以下是使用语句对象的批处理的典型步骤
注册驱动获取连接
使用createStatement()方法创建Statements对象
使用setAutoCommit()将auto_commit设置为false
使用使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中
在创建的语句对象上使用executeBatch()方法执行所有SQL语句
使用commit()方法提交所有更改
释放资源
  • 经典步骤
package waking.test.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Statement批处理
 * @author waking
 *
 */
public class Demo10 {
	public static void main(String[] args) {
		// 驱动
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 声明连接
		Connection conn = null;
		Statement stmt = null;
		
		try {
			// 加载驱动
			Class.forName(dirver);
			// 创建连接
			conn = DriverManager.getConnection(url, user, password);
			// 查询
			stmt = conn.createStatement();
			// 开启事务
			conn.setAutoCommit(false);
			// 返回结果
			// sql语句
			String sql1 = "insert into user values(8,'waki','wakig','xixix','17273934784')";
			stmt.addBatch(sql1);
			String sql2 = "insert into user values(9,'wa','wak','hee','17273934784')";
			stmt.addBatch(sql2);
			int[] executeBatch = stmt.executeBatch();
			// 提交事务
			conn.commit();
			System.out.println("影响"+executeBatch.length+"行");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			// 关闭连接
			if(stmt!=null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
  • 简易步骤
// 以上开启事务和关闭事务可以省略
String sql1 = "insert into user values(8,'waki','wakig','xixix','17273934784')";
			stmt.addBatch(sql1);
			String sql2 = "insert into user values(9,'wa','wak','hee','17273934784')";
			stmt.addBatch(sql2);
			int[] executeBatch = stmt.executeBatch();
PrepareStatement批处理
使用占位符创建SQL语句
使用PrepareStatement()方法创建PrepareStatement对象
使用setAutoCommit()将auto_commit设置为false
使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理
在创建的语句对象上使用executeBatch()方法执行所有SQL语句
最后,使用commit()方法提交所有更改
package waking.test.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * PreparedStatement批处理
 * @author waking
 *
 */
public class Demo11 {
	public static void main(String[] args) {
		// 驱动
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 声明连接
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try {
			// 加载驱动
			Class.forName(dirver);
			// 创建连接
			conn = DriverManager.getConnection(url, user, password);
			// 查询
			// sql语句
			String sql1 = "insert into user values(?,?,?,?,?)";
			// 8,'waki','wakig','xixix','17273934784'
			pstmt = conn.prepareStatement(sql1);
			// 开启事务
			conn.setAutoCommit(false);
			
			pstmt.setInt(1, 10);
			pstmt.setString(2, "wakk");
			pstmt.setString(3, "fdas");
			pstmt.setString(4, "asa");
			pstmt.setString(5, "17273934784");
			pstmt.addBatch();	
			
			pstmt.setInt(1, 11);
			pstmt.setString(2, "akk");
			pstmt.setString(3, "fs");
			pstmt.setString(4, "aa");
			pstmt.setString(5, "17273934784");
			pstmt.addBatch();
			// 返回结果
			int[] executeBatch = pstmt.executeBatch();
			// 提交事务
			conn.commit();
			System.out.println("影响"+executeBatch.length+"行");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			// 关闭连接
			if(pstmt!=null) {
				try {
					pstmt.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
Statment批处理和PrepareStatement批处理区别
  • Statement批处理可以添加不同SQL语句,而PrepareStatement只能添加一种SQL语句
  • PrepareStatement效率比Statement高,而且更安全

数据库事务

事务概述
  • 一组要么同时执行成功,要么同时失败的SQL语句。是数据库操作的一个不能分割执行单元
数据库事务(Database Transaction),是指作为单个逻辑单元执行的一系列操作,要么完全的执行,要么完全的不执行。
事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更可靠。
一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性,一致性,隔离性,持久性)属性。
事务是数据库运行中的逻辑工作单位,有DBMS中的事务管理子系统负责事务的处理。
通常事务开始于
  • 连接到数据库上,并执行一条DML语句insert,update或delete
  • 前一个事务结束后,又输入了另一条DML语句
通常事务结束于
  • 执行commit后rollback语句
  • 执行一条DDL语句,列如create table语句,在这种情况下,会自动执行commit语句
  • 断开与数据库的连接
  • 执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback语句
事务特性(ACID)
  • Atomicity(原子性)
    • 表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
  • Consistency(一致性)
    • 表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
  • Isolation(隔离性)
    • 事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据
  • Durability(持久性)
    • 持久性事务完成之后,它对于系统的影响是永久的
  • 数据库操作
CREATE TABLE account(
	id INT PRIMARY KEY,
	NAME VARCHAR(20)NOT NULL,
	money DOUBLE(10,2)
);
INSERT INTO account(id,NAME,money) VALUES(1,'wkaing',100),(2,'lily',100);
  • java代码
package waking.test.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 事务处理
 * @author waking
 *
 */
public class Demo12 {
	public static void main(String[] args) {
		// 驱动
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 声明连接
		Connection conn = null;
		PreparedStatement pstmt1 = null;
		PreparedStatement pstmt2 = null;
		try {
			// 加载驱动
			Class.forName(dirver);
			// 创建连接
			conn = DriverManager.getConnection(url, user, password);
			// 开启事务
			conn.setAutoCommit(false);
			// 查询
			// sql语句
			String sql1 = "update account set money = money - 100 where id = ?";
			String sql2 = "update account set money = money + 100 where id = ?";
			pstmt1 = conn.prepareStatement(sql1);
			
			pstmt1.setInt(1, 1);
			// 返回结果
			pstmt1.executeUpdate();
			
			pstmt2 = conn.prepareStatement(sql2);
			pstmt2.setInt(1, 2);
			pstmt2.executeUpdate();
			System.out.println("转账成功、、");
			// 提交事务
			conn.commit();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("转账失败、、、");
			try {
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally {
			// 关闭连接
			if(pstmt1!=null) {
				try {
					pstmt1.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(pstmt2!=null) {
				try {
					pstmt2.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
Mysql事务语句
#开启事务
START TRANSACTION;
UPDATE account SET money = money-100 WHERE id =1;
UPDATE account SET money = money+100 WHERE id =2;
#提交事务
COMMIT;
#回滚事务
ROLLBACK;

事务的隔离级别

  • 一个事务,在并发访问的情况下,不同隔离级别会出现不同效果
  • 并发:在同一时刻,有多个客户在操作同一张表
1.read uncommitted
一个事务中读到了另一个事务并未提交的结果。
这种隔离级别就会导致:脏读、不可重复读、幻读
2.read committed (oracle的默认隔离级别)
一个事务中能读到另一个事务已经提交的结果,但是不能读到另一个事务没有提交的结果
这种隔离级别解决了脏读问题。但出现了不可从重复读和幻读的问题
注:
所谓的不可重复读,就是不能重复读,一重复读数据就不一样
所谓的幻读,在一个事务中,两次读到的数据的条数不相同
3.repeatable read(mysql的默认级别)
一个事务中可以重复读,每次读到的数据都是一样的
无论其他事务对数据进行怎样的操作(添加数据、修改数据、提交事务)。当前事务每次读到的数据内容都不会有变化
这种隔离级别解决了:脏读、不可重复读,幻读
4.serializable串行化
最严苛的隔离级别。将并行变成串行。效率非常低。
  • mysql查看事务隔离级别
    • select @@tx_isolation
  • 设置隔离级别
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
Savepoint
  • Connection对象有两种新的方法来帮助您管理保存点 -
  • setSavepoint(String savepointName):定义新的保存点。它还返回一个Savepoint对象。
  • releaseSavepoint(Savepoint savepointName):删除保存点。请注意,它需要一个Savepoint对象作为参数。此对象通常是由setSavepoint()方法生成的保存点。
package waking.test.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;

/**
 *  事务处理
 *  savepoint
 * @author waking
 *
 */
public class Demo13 {
	public static void main(String[] args) {
		// 驱动
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 声明连接
		Connection conn = null;
		Statement stmt = null;
		Savepoint savepoint=null;
		try {
			// 加载驱动
			Class.forName(dirver);
			// 创建连接
			conn = DriverManager.getConnection(url, user, password);
			// 开启事务
			conn.setAutoCommit(false);
			// 查询
			// sql语句
			String sql = "update account set money = money - 100 where id = 1";
			
			stmt = conn.createStatement();
			stmt.executeUpdate(sql);
			savepoint= conn.setSavepoint("save");

			String sql1 = "update account set money = money + 100 where id = 2";
			
			stmt.executeUpdate(sql1);
			conn.commit();
			System.out.println("转账成功、、");
			// 提交事务
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("转账失败、、、");
			try {
				//回滚事务
				conn.rollback(savepoint);
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally {
			// 关闭连接
			if(stmt!=null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
感谢您的观看
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值