JDBC_02
A.抽取jdbc工具类
1.概述
在我Java链接数据库中,需要一系列的步骤
但在开发中,不可能每次都要写这么长的步骤
所以,我们可以将这些步骤抽取到一个工具类中
这样在链接数据库时,直接调用即可,减少代码的复用性
2.工具类
工具类一旦写好,尽量避免改动
但我们每次链接的数据库不同,帐号密码也不同
因此我们需要建立一个配置文件,存放这些参数
只需要通过集合properties.load()方法
或者ResourceBundle工具(代码中解释)从文本中读取配置信息即可
当我们需要更改数据库配置信息,只需要更改配置文件即可
在src文件下创建一个配置文件jdbc.properties
工具类url=jdbc:mysql://localhost:3306/mydb_01 user=root password=root driverClass=com.mysql.jdbc.Driver
测试类import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ResourceBundle; // 工具类 public class JDBCUtil { private static String url; private static String user; private static String password; private static String driverClass; // 静态代码块,随着类的加载而执行 // 读取配置信息并加载驱动,只要调用类,就加载 static { try { // 方式1 properties // 创建集合 // Properties prop = new Properties(); // 读取配置信息 // prop.load(new FileInputStream("src//jdbc.properties")); // url = prop.getProperty("url"); // user = prop.getProperty("user"); // password = prop.getProperty("password"); // 加载驱动 // Class.forName(prop.getProperty("driverClass")); // 方式2 ResourceBundle工具 // 如果一个文件在src目录下 而且键值对数据是以"="连接 并且文件后缀名是.properties // 1)获取对象 ResourceBundle bundle = ResourceBundle.getBundle("jdbc"); // 不带后缀名 url = bundle.getString("url"); user = bundle.getString("user"); password = bundle.getString("password"); driverClass = bundle.getString("driverClass"); // 加载驱动 Class.forName(driverClass); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 不让外界创建对象,私有构造 private JDBCUtil() { super(); } // 获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } // 释放资源 public static void close(Connection conn, Statement statement, ResultSet resultSet) throws SQLException { // 非空判断 if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (conn != null) { conn.close(); } } // 如果没有返回结果集,方法重载 public static void close(Connection conn, Statement statement) throws SQLException { // 非空判断 if (statement != null) { statement.close(); } if (conn != null) { conn.close(); } } }
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.xxxx.jdbc.utils.JDBCUtil; // 测试类 public class JDBCDemo01 { public static void main(String[] args) throws SQLException { // 拷jar包 // 获取链接对象 Connection conn = JDBCUtil.getConnection(); // 定义sql语句 String sql = "select * from user where username=?"; // 获取预编译对象 PreparedStatement statement = conn.prepareStatement(sql); // 给占位符赋值 statement.setString(1, "张三"); // 执行语句 ResultSet resultSet = statement.executeQuery(); // 处理结果 while (resultSet.next()) { int id = resultSet.getInt("id"); String username = resultSet.getString("username"); System.out.println(id + "---" + username); } // 释放资源 JDBCUtil.close(conn, statement, resultSet); } }
B.事物
1.模拟银行转账
现在数据库中创建一个表
现在需求是张三给李四转账1000CREATE TABLE bank( username VARCHAR(50), money INT ); INSERT INTO bank VALUES('张三', 5000); INSERT INTO bank VALUES('李四', 100); SELECT * FROM bank;
查看结果import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import org.xxxx.jdbc.utils.JDBCUtil; public class Demo01 { public static void main(String[] args) { // 拷jar包 Connection conn = null; PreparedStatement statement1 = null; PreparedStatement statement2 = null; try { // 建立连接 conn = JDBCUtil.getConnection(); // 定义sql语句 String sql1 = "update bank set money=money-1000 where username=?"; // 账户转出 String sql2 = "update bank set money=money+1000 where username=?"; // 账户转入 // 获取预编译对象 statement1 = conn.prepareStatement(sql1); statement2 = conn.prepareStatement(sql2); // 给?赋值 statement1.setString(1, "张三"); statement2.setString(1, "李四"); // 执行语句 statement1.executeUpdate(); statement2.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { // 释放资源 try { JDBCUtil.close(null, statement2); JDBCUtil.close(conn, statement1); } catch (SQLException e) { e.printStackTrace(); } } } }
现在制造一个异常来模拟:当张三将钱转出去,服务器发生异常,强制终止
给执行语句中间加一个异常
// 执行语句 statement1.executeUpdate(); // 加一个异常 System.out.println(1 / 0); statement2.executeUpdate();
会发现张三账户扣了钱,但李四没到帐这种情况在银行是不允许的,因此引入事物概念
2.概述
a.概念
事务指一组最小逻辑操作单元,里面由多个操作组成
组成事务的每一部分必须要同时提交成功
如果有一个操作失败,整个操作就回滚
b.特性
1)原子性:是一个最小逻辑操作单元
指事务是一个不可分割的工作单位
事务中的操作要么都发生,要么都不发生
2)一致性:事务过程中,数据处于一致状态
事务必须使数据库从一个一致性状态变换到另外一个一致性状态
3)隔离性:事务与事务之间是隔离的
多个用户并发访问数据库时,数据库为每一个用户开启的事务
不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离
4)持久性:事务一旦提交成功,对数据的更改会反映到数据库中
事务一旦被提交,它对数据库中数据的改变就是永久性的
接下来即使数据库发生故障也不应该对其有任何影响
3.事务回滚
针对上述银行账户问题,就要使用回滚来解决
Connection SetAutoCommit(boolean b):开启事物,默认为true,b=false则开启事物
Connection rollback():回滚事物到初始状态(当程序运行异常,张三李四账户余额不变)
Connection commit():提交事物
当程序发生异常,数据回滚到最初状态import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import org.xxxx.jdbc.utils.JDBCUtil; public class Demo01 { public static void main(String[] args) { // 拷jar包 Connection conn = null; PreparedStatement statement1 = null; PreparedStatement statement2 = null; try { // 建立连接 conn = JDBCUtil.getConnection(); // 开启事物 conn.setAutoCommit(false); // 定义sql语句 String sql1 = "update bank set money=money-1000 where username=?"; // 账户转出 String sql2 = "update bank set money=money+1000 where username=?"; // 账户转入 // 获取预编译对象 statement1 = conn.prepareStatement(sql1); statement2 = conn.prepareStatement(sql2); // 给?赋值 statement1.setString(1, "张三"); statement2.setString(1, "李四"); // 执行语句 statement1.executeUpdate(); // 加一个异常 System.out.println(1 / 0); statement2.executeUpdate(); } catch (Exception e) { // 一旦发生异常,回滚到最初状态 try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { // 提交事物 try { conn.commit(); } catch (SQLException e1) { e1.printStackTrace(); } // 释放资源 try { JDBCUtil.close(null, statement2); JDBCUtil.close(conn, statement1); } catch (SQLException e) { e.printStackTrace(); } } } }
4.事物回滚点
当程序中执行两次转账,第一次成功,第二次失败,回滚到初始状态
但我想第一转账成功保留,只会滚到第二次转账前的状态,怎么办?
需要设置一个回滚点
Connection setSavepoint():在两次之间设置一个回滚点
Connection rollback(Connection setSavepoint()):回滚到回滚点上
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Savepoint; import org.xxxx.jdbc.utils.JDBCUtil; public class Demo01 { public static void main(String[] args) { // 拷jar包 Connection conn = null; PreparedStatement statement1 = null; PreparedStatement statement2 = null; Savepoint savepoint = null; try { // 建立连接 conn = JDBCUtil.getConnection(); // 开启事物 conn.setAutoCommit(false); // 定义sql语句 String sql1 = "update bank set money=money-1000 where username=?"; // 账户转出 String sql2 = "update bank set money=money+1000 where username=?"; // 账户转入 // 第一次转账 // 获取预编译对象 statement1 = conn.prepareStatement(sql1); statement2 = conn.prepareStatement(sql2); // 给?赋值 statement1.setString(1, "张三"); statement2.setString(1, "李四"); // 执行语句 statement1.executeUpdate(); statement2.executeUpdate(); // 设置回滚点 savepoint = conn.setSavepoint(); // 第二次转账 // 执行语句 statement1.executeUpdate(); // 加一个异常 System.out.println(1 / 0); statement2.executeUpdate(); } catch (Exception e) { // 一旦发生异常,回滚到最初状态 try { conn.rollback(savepoint); // 回滚到指定回滚点 } catch (SQLException e1) { e1.printStackTrace(); } } finally { // 提交事物 try { conn.commit(); } catch (SQLException e1) { e1.printStackTrace(); } // 释放资源 try { JDBCUtil.close(null, statement2); JDBCUtil.close(conn, statement1); } catch (SQLException e) { e.printStackTrace(); } } } }
第一次转账成功,第二次发生异常
在两次之间设置了一个回滚点,使得正确执行的部分得以保留
C.调用存储过程
1.概述
有时为了提高效率,需要执行存储过程语句
2.调用存储过程
Connection prepareCall(sql):创建存储过程对象
建立一个存储过程
调用存储过程DELIMITER $ CREATE PROCEDURE pro_bank() BEGIN SELECT * FROM bank; END $
import java.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import org.xxxx.jdbc.utils.JDBCUtil; public class Demo01 { public static void main(String[] args) { // 拷jar包 Connection conn = null; CallableStatement prepareCall = null; ResultSet resultSet = null; try { // 创建连接 conn = JDBCUtil.getConnection(); // 定义sql语句 String sql = "call pro_bank"; // 创建存储过程对象 prepareCall = conn.prepareCall(sql); // 执行sql语句 resultSet = prepareCall.executeQuery(); // 查看结果 while (resultSet.next()) { String username = resultSet.getString("username"); int money = resultSet.getInt("money"); System.out.println(username + "---" + money); } } catch (SQLException e) { e.printStackTrace(); } finally { // 释放资源 try { JDBCUtil.close(conn, prepareCall, resultSet); } catch (SQLException e) { e.printStackTrace(); } } } }
本文介绍如何通过Java JDBC工具类简化数据库操作,并探讨事务处理及存储过程调用等高级主题。
3642

被折叠的 条评论
为什么被折叠?



