tanyhuan 2020-02-18
一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
开启事务
提交事务
回滚事务
java.sql.Connection接口是一个数据库连接对象。它与特定数据库的连接(会话)。 执行SQL语句并在连接的上下文中返回结果。
setAutoCommit(boolean autoCommit) // 调用该方法设置参数为false,即开启事务
commit() // 当所有sql都执行完提交事务
rollback() // 在catch中回滚事务
有如下一个MySQL数据表,利用Java程序:把id = 1对应的余额减少500,id = 2对应的余额增加500
CREATE TABLE account ( id INT PRIMARY KEY AUTO_INCREMENT, -- id NAME VARCHAR(10), -- 名字 balance DOUBLE -- 余额 ); INSERT INTO account (NAME, balance) VALUES (‘LeeHua‘, 1000), (‘Tom‘, 1000);
自定义一个注解,获取连接数据库的信息:
package my.view.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) // 注解能作用于类上 @Retention(RetentionPolicy.RUNTIME) // 当前被描述的注解,会保留到class字节码文件中,并被JVM读取到 public @interface PropertiesAnnotation { /* URL */ public abstract String url(); /* 用户 */ public abstract String user(); /* 密码 */ public abstract String password(); /* 驱动包 */ public abstract String driver(); }
定义一个工具类,用来注册驱动和获取数据库连接对象:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; @PropertiesAnnotation( url = "jdbc:mysql:///Study", user = "账号", password = "密码", driver = "com.mysql.jdbc.Driver" ) public class JdbcUtils02 { private static String url; private static String user; private static String password; private static String driver; /* 文件的读取,只需要读取一次即可拿到这些值。利用反射和注解、使用静态代码块 */ static{ // 读取资源文件,获取值。 try { // 1. 解析注解 // 1.1 获取JdbcUtils02类的字节码文件对象 Class<JdbcUtils02> jdbcUtils02Class = JdbcUtils02.class; // 2. 获取上边的注解对象 PropertiesAnnotation annotation = jdbcUtils02Class.getAnnotation(PropertiesAnnotation.class); // 3. 调用注解中定义的抽象方法,获取返回值,赋值给静态成员变量 url = annotation.url(); user = annotation.user(); password = annotation.password(); driver = annotation.driver(); // 4. 注册驱动 Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 获取连接 * @return 连接对象 */ public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } }
有了以上条件,对数据表进行操作:
Connection connection = JdbcUtils02.getConnection();
connection.setAutoCommit(false);
String sql1 = "update account set balance = balance - ? where id = ?"; String sql2 = "update account set balance = balance + ? where id = ?";
PreparedStatement preparedStatement1 = connection.prepareStatement(sql1); PreparedStatement preparedStatement2 = connection.prepareStatement(sql2);
// LeeHua 的账户余额减少500元 preparedStatement1.setDouble(1,500); preparedStatement1.setInt(2,1); // Tom 的账户余额增加500元 preparedStatement2.setDouble(1,500); preparedStatement2.setInt(2,2);
preparedStatement1.executeUpdate(); preparedStatement2.executeUpdate();
connection.commit();
connection.rollback();
releaseResources(preparedStatement2); releaseResources(preparedStatement1); releaseResources(connection);
/** * 释放资源 * @param t 要被释放的资源 * @param <T> 要被释放的资源对象的类型 */ public static <T> void releaseResources (T t){ if(t != null){ try { // 利用反射,获取class对象 Class<?> aClass = t.getClass(); // 获取class对象中的方法对象 Method close = aClass.getMethod("close"); // 执行方法 close.invoke(t); } catch (Exception e) { e.printStackTrace(); } } }
对数据表进行操作的实现代码如下:
package my.view.jdbc; import my.view.util.JdbcUtils02; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class JdbcDemo09 { public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement1 = null; PreparedStatement preparedStatement2 = null; try { // 1. 获取连接 connection = JdbcUtils02.getConnection(); // 开启事务 connection.setAutoCommit(false); // 2. 定义sql // 2.1 定义减少账户余额的SQL语句 String sql1 = "update account set balance = balance - ? where id = ?"; // 2.2 定义增加账户余额的SQL语句 String sql2 = "update account set balance = balance + ? where id = ?"; // 3.获取执行SQL语句的对象 preparedStatement1 = connection.prepareStatement(sql1); preparedStatement2 = connection.prepareStatement(sql2); // 4. 设置参数 // 4.1 LeeHua 的账户余额减少500元 preparedStatement1.setDouble(1,500); preparedStatement1.setInt(2,1); // 4.2 Tom 的账户余额增加500元 preparedStatement2.setDouble(1,500); preparedStatement2.setInt(2,2); // 5. 执行SQL语句 preparedStatement1.executeUpdate(); preparedStatement2.executeUpdate(); // 6. 提交事务 connection.commit(); } catch (Exception e) { // 7. 事务回滚 try { if(connection != null) { connection.rollback(); } } catch (SQLException e1) { e1.printStackTrace(); } } finally { // 8. 释放资源 releaseResources(preparedStatement2); releaseResources(preparedStatement1); releaseResources(connection); } } /** * 释放资源 * @param t 要被释放的资源 * @param <T> 要被释放的资源对象的类型 */ public static <T> void releaseResources (T t){ if(t != null){ try { // 利用反射,获取class对象 Class<?> aClass = t.getClass(); // 获取class对象中的方法对象 Method close = aClass.getMethod("close"); // 执行方法 close.invoke(t); } catch (Exception e) { e.printStackTrace(); } } } }
运行程序,查看表中的记录,发现LeeHua的账号余额减少了500,Tom的账户余额增加了500。