您的位置:首页 > 编程语言 > Java开发

【JavaEE学习笔记】JDBC_02_抽取jdbc工具类,事物,调用存储过程

2017-10-07 14:40 721 查看
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.模拟银行转账

现在数据库中创建一个表

CREATE TABLE bank(
username VARCHAR(50),
money INT
);

INSERT INTO bank VALUES('张三', 5000);
INSERT INTO bank VALUES('李四', 100);

SELECT * FROM bank;
现在需求是张三给李四转账1000

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();
}
}
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐