03_JavaWeb||day05_JDBC基础【重点掌握】||day05_1_JDBC基础【重点掌握第五点和会使用JDBCUtils工具类,了解JDBC事务处理位置即可】
其他
2020-04-24 20:36:59
阅读次数: 0
今日内容【重点掌握】
JDBC基本概念
快速入门
对JDBC中各个接口和类详解
1. JDBC:
概念 :Java数据库连接(Java DataBase Connectivity)
JDBC本质 :
其实是官方(sun公司)定义的一套操作++所有关系型数据库的规则++,即接口 。
各个数据库厂商去实现这套接口,提供数据库驱动jar包。
我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
快速入门 :
步骤:
导入驱动jar包(mysql-connector-java-5.1.37-bin.jar)
复制到项目的libs目录下
右键libs文件–>Add As Library(这样了才真正的加入到了项目中)
注册驱动(编写代码) Class.forName("com.mysql.jdbc.Driver");
Class.forName("");的作用是将代码加载进内存
会有异常:正常写的时候要处理
获取数据库的连接对象(Connection) //数据库db3的url,账号,密码
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "password");
定义sql String sql = "update account set balance = 500 where id = 1";
获取执行sql语句的对象(Statement) Statement stmt = conn.createStatement();
执行sql,接收返回结果 int count = stmt.executeUpdate(sql);
处理结果 System.out.println(count);
释放资源 stmt.close();
conn.close();
++详解各个对象++ : 1. ++DriverManager:驱动管理对象++
是一个类
功能:
注册驱动 :告诉程序该使用哪一个数据库驱动jar包
方法 :static void registerDriver (Driver driver):注册与给定的驱动程序(DriverManager)
写代码时使用的是 :Class.forName(“com.mysql.jdbc.Driver”);【重点掌握】 //作用是将代码(类文件)加载进内存
所以底层实现就是DriverManager,只不过使用Class.forName(“com.mysql.jdbc.Driver”);简单【总结】
注:mysql之后的驱动jar包可以省略注册驱动的步骤【一般写上】
在jar包–>META-INF–>services–>java.sql.Driver中
注:Class.forName会有异常:正常写的时候要处理
获取数据库连接
方法:static Connection getConnection (String url, String user, String password);//静态方法,可以直接通过类名调用
这个也是会抛出异常,和Class.forName抛出的异常放到一起
参数:
url:指定连接的路径
user:用户名
password:密码
2. ++Connection:数据库连接对象++
功能:
获取执行sql的对象
管理事务
开启事务:void setAutoCommit (boolean autoCommit):调用该方法设置参数为false(自动变为手动),即为开启事务
提交事务:commit ()
回滚事务:rollback ()
3. ++Statement:执行sql的对象【重点】++
功能:
执行sql
方法:
boolean execute (String sql):可以执行任意的sql–>(了解)
int executeUpdate (String sql):【重点掌握】 –>执行DML (增删改insert,delete,update)语句、DDL(表和库的操作create,alter,drop)语句
注:返回值就是执行语句影响的行数
执行DDL的时候不返回(默认0)
可以通过这个影响的行数判断DML语句是否执行成功,返回值>0则执行成功,反之,则失效
ResultSet executeQuery (String sql):【重点掌握】 –>执行DQL(查询select)语句
返回值是:结果集对象(就是查询sql后显示的呢个结果)
练习:
account表 添加一条记录(insert)
注:释放资源放到finally里面(不管代码对不对都要释放)
导入sql包不要看错了
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
Statement stmt = null;
Connection conn = null;
try {
//1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2. 定义sql
String sql = "INSERT INTO account value(null, '王五', 3000)";
//3. 获取Connection对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "password");
//4. 获取执行sql的对象:Statement
stmt = conn.createStatement();
//5. 执行sql
int count = stmt.executeUpdate(sql); //影响的行数
//处理的结果
System.out.println(count);
if(count > 0) {
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//为了避免空指针异常
//7. 释放资源
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
account表 修改记录
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Test2 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
//1. 驱动注册
Class.forName("com.mysql.jdbc.Driver");//**
//2. 编写sql
String sql = "UPDATE account SET balance=1500 WHERE id=3";
//3.创建Connection对象
conn = DriverManager.getConnection("jdbc:mysql://localhost.3306/db3", "root", "password");
//4. 获取执行sql对象
stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);
//6.执行结果
System.out.println(count);
if(count > 0) {
System.out.println("执行成功");
}else {
System.out.println("执行失败");
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//7.释放资源
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
account表 删除一条记录
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Test3 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
//1.驱动注册
Class.forName("com.mysql.jdbc.Driver");
//2.sql语句
String sql = "DELETE FROM account WHERE id = 3";
//3.获取Connection对象
conn = DriverManager.getConnection("jdbc:mysql://localhost.3306/db3", "root", "password"); //***
//4.获取执行sql对象
stmt = conn.createStatement();
//5.执行sql语句
int count = stmt.executeUpdate(sql);
//6.执行结果
System.out.println(count);
if(count > 0) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
4. ++ResultSet:结果集对象(用来封装查询结果)++
意义:从ResultSet结果集对象中,把查出来的结果数据拿出来
默认在第一行,所以先向下
执行方法让游标一行一行向下进行数据获取
方法:
boolean next ():++游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果没有数据,返回false++
getXxx (参数):获取数据
Xxx:代表数据类型
比如获取id的时候getInt()
获取name的时候getString()
参数:(体现了方法的重载)
Int:代表列的编号(从1开始)
String:代表列的名称。
演示:(将来不是这样使用的 ,这里只是基本使用)
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test4 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.sql语句
String sql = "SELECT * FROM account";
//3.获取Connection对象
conn = DriverManager.getConnection("jdbc:mysql://localhost.3306/db3", "root", "password");
//4.创建获取执行sql对象
stmt = conn.createStatement();
//5.执行sql(DQL-->用executeQuery)
rs = stmt.executeQuery(sql);
//6. 执行结果(获取的数据)
//6.1先让游标向下移动一行
rs.next();
//6.1获取数据
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble("balance");
//打印
System.out.println(id + "---" + name + "---" + balance);
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
ResultSet真正使用方式
游标向下移动一行
判断是否有数据
获取数据
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test5 {
public static void main(String[] args) {
ResultSet rs = null;
Statement stmt = null;
Connection conn = null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.sql语句
String sql = "SELECT * FROM account";
//3.获取Connection对象
conn = DriverManager.getConnection("jdbc.mysql://localhost.3306/db3", "root", "password");
//4.获取执行sql对象
stmt = conn.createStatement();
//5.执行sql(DQL-->Query)
rs = stmt.executeQuery(sql);
//6. 执行结果(获取的数据)
//循环判断游标是否是最后一行末尾
while(rs.next()) {
//6.1获取数据
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble("balance");
//打印
System.out.println(id + "---" + name + "---" + balance);
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
练习:
定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
定义Emp类
定义方法 public List findAll(){}
实现方法 select * from emp;
//Emp类(JavaBean)
public class Emp {
private int id;
private String balance;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBalance() {
return balance;
}
public void setBalance(String balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", balance='" + balance + '\'' +
'}';
}
}
//JdbcDemo类
import java.sql.*;
import java.util.LinkedList;
import java.util.List;
public class JdbcDemo {
public static void main(String[] args){
List<Emp> list = new JdbcDemo().findAll();
System.out.println(list);
}
public List<Emp> findAll(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Emp> listA = null;
try {
//1注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2sql语句
String sql = "SELECT * FROM emp";
//3获取Connection对象
conn = DriverManager.getConnection("jdbc:mysql://localhost.3306/db3", "root", "psaaword");
//4.获取执行sql的对象
stmt = conn.createStatement();
//5.执行sql(查询的DQL,所以query)
rs = stmt.executeQuery(sql);
Emp emp = null;
//因为要返回所以写在外面
listA = new LinkedList<>(); //用来存储信息的集合
//获取信息后存到集合中
while (rs.next()){ //判断下一行是否有值
//先获取到数据库里面的值
int id = rs.getInt("id");
String balance = rs.getString("balance");
//创建emp对象并赋值
emp = new Emp();
//将值添加到emp类中
emp.setId(id);
emp.setBalance(balance);
//加到集合中
listA.add(emp);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return listA;
}
}
5. ++PreparedStatement:表示预编译sql语句的对象【开发真正用的】(功能更多)++
Statement接口的子接口
注:浏览顺序,先看JDBC工具类在回头来看该内容
JDBC工具类中综合案例出现的问题:SQL注入问题【重点】
SQL注入概念【*】 :在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。(会造成安全问题)
输入用户随便(gxw),输入密码(特殊密码): //输入的特殊密码
a' or 'a' = 'a
就会生成一段sql语句 select * form user where username='gxw' and password='a' or 'a' = 'a'
or之前确实是false但是后面加的为true,or是或运算,所有就恒等于true了(就很危险)
++解决SQL注入问题++:使用PreparedStatement对象来解决
预编译的sql【重点】 :参数使用?作为占位符
步骤【真正要掌握的 】:
导入驱动jar包(mysql-connector-java-5.1.37-bin.jar)
注册驱动(编写代码)
Class.forName("");的作用是将代码加载进内存
获取数据库的连接对象(Connection)
定义sql
获取执行sql语句的对象(PreparedStatement )
调用:Connection.prepareStatement (String sql)方法
给?去赋值 :
执行sql,接收返回结果(这里就不需要传递sql语句了 )
处理结果
释放资源
优化JDBC工具类中的登录方法: public class JdbcTest1 {
public static void main(String[] args) {
//输入账号和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号");
String username = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();
boolean login = new JdbcTest1().login(username, password);//非静态方法
if(login){
System.out.println("登录成功");
}else {
System.out.println("账号或者密码错误");
}
}
/*
* 登录方法,使用PreparedStatement实现
*/
public boolean login(String username, String password){
if(username == null || password == null){
return false;
}
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//1.获取资源
conn = JDBCUtils.getConnection();
//2.sql语句
String sql = "SELECT * FROM username=? AND password=?";
//3.获取执行sql的对象
pstmt = conn.prepareStatement(sql);
//4.给?号赋值
pstmt.setString(1, username);
pstmt.setString(2, password);
//5.执行sql,不需要传递参数
rs = pstmt.executeQuery();
//判断
return rs.next(); //有下一行则返回true
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs, pstmt, conn);
}
return false;
}
}
注意:后期都会使用PreparedStatement来完成增删改查的所有操作【重点】
防止SQL注入
效率更高
2. 抽取JDBC工具类 : JDBCUtils【工具类重点,会使用即可】
目的:简化书写
分析:【抽取的:注册驱动,获取连接对象,释放资源】
注册驱动 也抽取
抽取一个方法获取连接对象【DriverManager.getConnection】
需求:++不想传递参数(麻烦),还得保证工具类的通用性。++
解决:配置文件 jdbc.properties url= user= password=
抽取一个方法释放资源
代码实现【*】:
//数据库db3的位置
url=jdbc:mysql:///db3
user=root
password=root
driver=com.mysql.jdbc.Driver
public class JDBCUtils {
//先声明4个静态成员变量
private static String url;
private static String user;
private static String password;
private static String driver;
/**
* 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
*/
static{
//读取资源文件,获取值。
try {
//1. 创建Properties集合类。
Properties pro = new Properties();
//获取src路径下的文件的方式--->ClassLoader 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath(); //System.out.println(path);///D:/IdeaProjects/itcast/out/production/day04_jdbc/jdbc.properties
//2. 加载文件
pro.load(new FileReader(path));//读取字符文件
//3. 获取数据,赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4. 注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return 连接对象
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
/**
* 释放资源【dml时候,增删改时】
* @param stmt
* @param conn
*/
public static void close(Statement stmt,Connection conn){
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 释放资源【dql时候,查询时】
* @param rs
* @param stmt
* @param conn
*/
public static void close(ResultSet rs,Statement stmt, Connection conn){
if( rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
什么时候使用静态代码块
如果需要程序在启动之前就进行一些操作 ,以及一些经常用到却不占用多少内存的代码或变量直接写在static静态代码块中,当程序启动的时候随之初始化,这样可以节省部分后续操作的时间
格式: static{
}
ClassLoader 类加载器【先了解】
作用
获取src路径下的(资源路径)文件的方式
可以来加载我们的字节码文件进内存
(JDBC工具类获取配置文件路径的)使用步骤【重点】
获取到ClassLoader,首先获取到对应的字节码文件对象
类名.class对象
其中一个getClassLoader()方法 :获取到ClassLoader
ClassLoader classloader = JDBCUtils.class.getClassLoader();
ClassLoader一个方法:getResource (String name):传入一个文件名(配置文件),就可以获取Resource资源。
++返回的是一个URL对象(表示:统一资源标识符/定位符):可以用来定位一个文件的绝对路径++
URL res = classloader.getResource("jdbc.properties");
使用URL对象的一个方法,getPath ():可以获取一个字符串路径 String path = res.getPath();
最后就可以将获取到的path,写到加载文件中了(上面三步就可以获取对应的资源文件的绝对路径了)
Properties集合类
双列集合,键值都是String,唯一一个可以直接结合IO流使用的集合类 ,++从流中读取文件,直接写入文件到流中++
读取资源文件获取值的步骤
创建Properties集合类 Properties pro = new Properties();
加载文件:
Properties集合类中load()方法 :从字节输入流中读取键值对 。参数中使用了字节输入流,通过流对象,可以关联到某文件上,这样就能够加载文本中的数据了。文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。该方法常用于读取配置文件
pro.load(new FileReader(path));
获取值
Properties集合类中getProperty()方法 :将搜索此属性列表中指定键的属性值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
演示JDBC工具类 import java.sql.*;
import java.util.LinkedList;
import java.util.List;
public class JdbcDemo {
public static void main(String[] args){
List<Emp> list = new JdbcDemo().findAll();
System.out.println(list);
}
public List<Emp> findAll(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Emp> listA = null;
try {
//注册驱动和获取Connection对象直接换成:
conn = JDBCUtils.getConnection();
//3sql语句
String sql = "SELECT * FROM emp";
//4.获取执行sql的对象
stmt = conn.createStatement();
//5.执行sql(查询的DQL,所以query)
rs = stmt.executeQuery(sql);
Emp emp = null;
//因为要返回所以写在外面
listA = new LinkedList<>(); //用来存储信息的集合
//获取信息后存到集合中
while (rs.next()){ //判断下一行是否有值
//先获取到数据库里面的值
int id = rs.getInt("id");
String balance = rs.getString("balance");
//创建emp对象并赋值
emp = new Emp();
//将值添加到emp类中
emp.setId(id);
emp.setBalance(balance);
//加到集合中
listA.add(emp);
}
} catch (SQLException e) { //ClassNotFoundException异常就不需要了
e.printStackTrace();
}finally {
//直接使用JDBCUtils工具类
JDBCUtils.close(rs, stmt, conn);
}
return listA;
}
}
练习:
需求(给db4数据库):
通过键盘录入用户名和密码
判断用户是否登录成功 * select * from user where username = "" and password = "";
步骤:
创建数据库表 user CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32),
PASSWORD VARCHAR(32)
);
INSERT INTO USER VALUES(NULL,'zhangsan','123');
INSERT INTO USER VALUES(NULL,'lisi','234');
代码实现:
//创建一个类:JdbcTest1
public class JdbcTest1 {
public static void main(String[] args) {
//输入账号和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号");
String username = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();
boolean login = new JdbcTest1().login(username, password);//非静态方法
if(login){
System.out.println("登录成功");
}else {
System.out.println("账号或者密码错误");
}
}
/*
登录方法
*/
public boolean login(String username, String password){
if(username == null || password == null){
return false;
}
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1.获取资源
conn = JDBCUtils.getConnection();
//2.sql语句
String sql = "SELECT * FROM user WHERE username='"+username+"' AND password='"+password+"'";
//3.获取执行sql的对象
stmt = conn.createStatement();
//4.执行sql
rs = stmt.executeQuery(sql);
//判断
return rs.next(); //有下一行则返回true
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs, stmt, conn);
}
return false;
}
}
注:定义sql语句时,里面传入的username和password都是字符串,所以拼接的时候别忘了单引号
存在的问题SQL注入问题,请看上面第五个内容有讲解【注】
3. 使用JDBC控制事务:
事务:一个包含多个步骤的业务操作。如果这个业务操作++被事务管理,则这多个步骤要么同时成功,要么同时失败++
操作JDBC事务处理的位置【重点】 :
开启事务:++执行sql之前++
在获取到Connection对象之后开启 –>(因为事务管理功能就属于Connection对象)
提交事务:++sql都执行完++
回滚事务:++catch中++
Connection对象的两个功能:
获取执行sql的对象
管理事务
所以使用Connection对象来管理事务
开启事务:void setAutoCommit (boolean autoCommit):调用该方法设置参数为false(false–>手动:开启事务后如果没有提交事务,就会回滚事务),(true–>自动:每次执行完自动提交事务)
提交事务:commit ()
回滚事务:rollback ()
案例:银行转账
/**
* 事务的操作
*/
public class JDBCDemo3 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
//1.获取数据库的链接
conn = JDBCUtils.getConnection();
///开启事务
conn.setAutoCommit(false);
//2.定义sql
//2.1张三-500
String sql1 = "UPDATE account SET balance = balance - ? WHERE id = ?";
//2.2李四+500
String sql2 = "UPDATE account SET balance = balance + ? WHERE id = ?";
//3.获取执行sql对象
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
//4.给?赋值
pstmt1.setDouble(1, 500);
pstmt1.setInt(2, 1);
pstmt2.setDouble(1, 500);
pstmt2.setInt(2, 2);
//5.执行sql语句(DML所以,使用executeUpdate)
pstmt1.executeUpdate();
//手动制造一点问题,但能否回滚(可以)
int i = 3 / 0;
pstmt2.executeUpdate();
///提交事务
conn.commit();
} catch (Exception e) { //一般抓一个大的异常,防止多次添加
///事务回滚
try {
if(conn != null){
conn.rollback();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
//这里写的不规范,只是为了演示事务
JDBCUtils.close(pstmt1, conn);
JDBCUtils.close(pstmt2, null);
}
}
}
发布了42 篇原创文章 ·
获赞 6 ·
访问量 1114
转载自 blog.csdn.net/qq_40572023/article/details/105524514