一、JDBC事务的概述
1、什么是JAVA事务
事务是一组原子操作单元,从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行有错误,则撤销先前执行过的所有指令。更简答的说就是:要么全部执行成功,要么撤销不执行。
- 原子性(atomicity):原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效。
- 一致性(consistency):一致性表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。
- 隔离性(isolation):隔离性表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
- 持久性(durability):持久性表示已提交的数据在事务执行失败时,数据的状态都应该正确。
2、为什么需要Java事务
事务是为解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问。
二、事务的类型
1、JDBC事务
JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。 java.sql.Connection 提供了以下控制事务的方法:
- 开启事务:void setAutoCommit(boolean autoCommit)
- 提交事务:void commit()
- 回滚事务: void rollback();
使用 JDBC 事务界定时,您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。
2、JTA(Java Transaction API)事务
JTA是一种高层的,与实现无关的,与协议无关的API,应用程序和应用服务器可以使用JTA来访问事务。
JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据,这些数据可以分布在多个数据库上。JDBC驱动程序的JTA支持极大地增强了数据访问能力。
3、容器事务
容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI(Java Naming and Directory Interface)的,相当复杂的API实现。
4、三种Java事务差异
JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。
JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。
容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用.
三、应用场景
1、数据库配置文件db.properties
# db connection parameters
driver=com.mysql.jdbc.Driver
#driver=oracle.jdbc.driver.OracleDriver
#driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:mysql://localhost:3306/test
#url=jdbc:oracle:thin:@localhost:1521:xe
#url=jdbc:sqlserver://localhost:1433;DatabaseName=demo
username=root
#username=demo
#username=sa
password=123456
2、数据库连接工具类
package com.wedu.demo;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String url;
private static String username;
private static String password;
private static String driver;
static {
Properties prop = new Properties();
try {
//1、加载配置文件
String path = JdbcUtils.class.getClassLoader().getResource("db.properties").getPath();
prop.load(new FileReader(path));
//2、获取加载的数据
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
driver = prop.getProperty("driver");
//3、注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接对象Connection
* @return 连接对象Connection
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
/**
* 释放资源
* @param st 执行sql语句对象
* @param conn 数据库连接对象
*/
public static void close(Statement st, Connection conn) {
if(st != null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 释放资源
* @param rs 结果集对象
* @param st 执行sql语句对象
* @param conn 数据库连接对象
*/
public static void close(ResultSet rs, Statement st, Connection conn) {
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st != null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3、jdbc事务事务操作
package com.wedu.demo;
import java.sql.*;
public class Demo {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1、获取数据库连接
conn = JdbcUtils.getConnection();
//2、开启事务
conn.setAutoCommit(false);
//3、定义Sql语句
String sql = "select * from userinfo where id = ?";
//4、获取执行sql的对象prepareStatement
ps = conn.prepareStatement(sql);
//5、为SQL语句中的参数赋值,注意,索引是从1开始的
ps.setInt(1, 4);
//6、执行操作
rs = ps.executeQuery();
//7、处理结果
while (rs.next()) {
String sitename = rs.getString("sitename");
String siteadress = rs.getString("siteadress");
System.out.println("网站名称:" + sitename + ",网站地址:" + siteadress);
}
//8、数据库操作完成后,提交事务
conn.commit();
} catch (SQLException e) {
try {
//9、如果操作数据库出现异常,回滚事务
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
//10、释放资源
JdbcUtils.close(rs, ps, conn);
}
}
}