事务的管理原则
- 原子性:
- 一致性:
- 隔离性:
JDBC中对事物的支持
JDBC默认是每执行一条 sql 语句都会提交事务。
这对于批处理数据来说性能开销过大。而且不满足事务本该管理的原则-上述三点
1:阻止事务自动提交
conn.setAutoCommit(false); // 不自动提交
2: conn.commit(); // 提交事务
3:conn.rollback();//回滚
批处理 sql
Statement的一个方法addBatch(String sql)方法。
该方法了几将给定的sql存入Statement的命令列表中缓存。
当执行executeBatch() 方法时,Statement会将命令列表中缓存的所有sql语句一次性提交给数据库。这可以有效的减少网络通信带来的性能消耗。
clearBath()用于清空命令表中缓存的所有sql语句。
preparedStatement 也支持批处理。原理相同
addBatch()不带参数 。想命令列表中添加一条sql语句
封装事务
Java提供了一个类ThreadLocal
该类的作用是, 在同一个线程中的不同模块间共享数据。
数据共享是根据线程区分的。不同线程间不共享数据。
举例:刷卡消费
每个人就是一个线程,他们在不同商店消费时,数据会互相影响
但是不同人之间的数据不会产生影响 就是不同线之间的数据不会共享
package day02.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;
/**
* DAO父类
*
* 基础类
* 提供所有的DAO 都需要兼备的特性
*
* @author ssd
*
*/
public class BaseDAO {
/**
* java.util.Properties类
* 用于读取properties文本文件类
* properties文件是一个纯文本的文件,里面的内容的定义有格式的要求
* 必须是key=value的形式,且以行为单位一行只记录一条数据
*properties类可以方便的读取properties文件,并将内容
*以类似HashMap的形式进行读取。注意!读取的都是字符串
*
*properties通常都是当做配置文件进行使用的。
*/
//共享同一个线程中数据的threadLocal
/**
* ThreadLocal 是在同一个线程中不同模块中共享数据使用过的
* ThreadLocal内部很简单
* 就是维护者一个HashMap
* 其中一个Key存放的是每一个线程
* value就是存放在不同模块之间要共享的数据
* 每个ThreadLocal实例,只能保存一个共享数据
* 不同的线程看到的是应该是同一个ThreadLocal实例,但是获取的
* 是不同的数据,因为在线程间不共享。每个线程在不同模块中共享数据
*
* 如果要想保存两个数据我们可以再建立一个ThreadLocal实例
*
*/
private static ThreadLocal<Connection> localConn = new ThreadLocal<Connection>();
private static Properties properties = new Properties();
private static String driver = "oracle.jdbc.driver.OracleDriver";
private static String url = "jdbc:oracle:thin:@localhost:1521:orcl";
private static String user = "scott";
private static String pwd = "Shen2014";
/**
* 在静态初始化中注册驱动
* 驱动不需要重复注册,所以静态初始化最适合注册驱动
* @return
*/
static {
try{
/**
* 加载配置文件,读取配置信息
*/
properties.load(BaseDAO.class.getClassLoader().getResourceAsStream("" +
"day02/dao/db.properties" ));
properties.load(BaseDAO.class.getClassLoader().getResourceAsStream("" +
"day02/dao/db.properties" ));
System.out.println(properties.getProperty("jdbc.driver"));
/**
* 通过Properties的方法getProperty(String key)
* 方法可以将properties文件中
* jdbc.driver=oracle.jdbc.driver.OracleDriver
* 数据获取。获得的方法就是将jdbc.driver作为参数调用方法
* 返回的就是等号右边的oracle.jdbc.driver.OracleDriver
*/
driver = properties.getProperty("jdbc.driver");
url = properties.getProperty("jdbc.url");
pwd = properties.getProperty("jdbc.pwd");
user = properties.getProperty("jdbc.user");
// 加载驱动
Class.forName(driver);
/**
* oracle.jdbc.driver.OracleDriver类
* 在Class.froName()的时候被载入JVM
* OracleDriver 是JDBC中的Driver 的子类
* 他被要求在静态初始化的时候要将自身驱动的信息
* 通过DriverManager 的静态方法注册进去,这样DriverManager就
* 知道应该如何通过OracleDriver去连接数据库了。
* 所以之后就可以公国DriverManager 的另一个静态方法:
* getConnection()来根据之前的注册的驱动信息来获取连接了。
*/
}catch (Exception e){
e.printStackTrace();
//若注册失败,我们要通知调用者
throw new RuntimeException(e);
}
}
/**
*提交事务
*/
protected void commit(){
/**
* 先去线程共享中看看当前调用搞该方法的线程是否共享过
* Connection,若有,就提交事务
*/
Connection conn = localConn.get();
if(conn != null){
try{
conn.commit();
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
* 事务回滚
*/
protected void rollback(){
Connection conn = localConn.get();
if(conn !=null){
try{
conn.rollback();
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
* 获取数据库连接对象Connection
* @return
* @throws SQLException 当连接失败时抛出异常
*/
protected static Connection getConnection() throws SQLException{
/**
* 当一个线程调用该方法要获取连接的时候,我们要先检查之前这个线程是否已经获取过一个连接了,若有,就不再
* 创建了
*/
Connection conn = localConn.get();
//若为空,说明这个线程第一次获取连接。
if(conn == null){
//穿件数据库的连接
conn = DriverManager.getConnection(url,user,pwd);
//将创建出来的连接放到线程共享中
localConn.set(conn);
}
return conn;
}
protected static void closeConnection (Connection conn){
if(conn != null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
package day02.entities;
import java.io.Serializable;
/**
* UserInfo实体类
* 对应数据库中的UserInfo表
* @author ssd
*
*/
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
private String id;
private String name;
private String password;
private int age;
private String sex;
private String email;
}
package day02.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import day02.entities.UserInfo;
/**
* 针对用户进行操作的DAO
* @author ssd
*
*/
public class UserInfoDAO extends BaseDAO {
/**
* SQL 语句常量定义
* @param userInfo
* @return
*/
private static final String INSERT = "INSERT INTO userinfo(" +
"id,name,password,age,sex,email" +
") VALUES(" +
"sys_guid(),?,?,?,?,?" +
")";
public boolean save(UserInfo userInfo){
return false;
}
public boolean save(List<UserInfo> userInfos){
Connection conn = null;
try {
conn = getConnection();
conn.setAutoCommit(false);
PreparedStatement state = conn.prepareStatement(INSERT);
long start = System.currentTimeMillis();
for(UserInfo userInfo:userInfos){
state.setString(1, userInfo.getName());
state.setString(2,userInfo.getPassword());
state.setInt(3, userInfo.getAge());
state.setString(4,userInfo.getSex());
state.setString(5,userInfo.getEmail());
state.addBatch();
}
state.executeBatch();//批处理执行之前缓存的所有的sql
conn.commit();//手动提交
long end = System.currentTimeMillis();
System.out.println("操作完成,耗时:" +(end - start) +
"毫秒");
return true ;//正常结束 返回一个true
}catch (Exception e){
e.printStackTrace();
//这个是在执行中间捕获的异常,就是在执行中间出现错误的时候我们要回滚
if(conn !=null){
try{
conn.rollback();
}catch(SQLException e1){
e1.printStackTrace();
}
}
}finally{
if(conn !=null){
try{
closeConnection(conn);
}catch(Exception e){
e.printStackTrace();
}
}
}
return false;
}
//创建表
public void createTable(){
Connection conn = null;
try{
conn = getConnection();
Statement state = conn.createStatement();
String sql = "CREATE TABLE userinfo(" +
"id varchar2(36) PRIMARY KEY," +
"name varchar2(30)," +
"password varchar2(50)," +
"age NUMBER (2)," +
"sex varchar2(2)," +
"email varchar2(50)" +
")";
if(!state.execute(sql)){
System.out.println("创建完毕");
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(conn !=null){
closeConnection(conn);
}
}
}
public static void main(String[] args){
UserInfoDAO dao = new UserInfoDAO();
dao.createTable();
}
}