基本概念

java DataBase Connectivity —> java数据库连接 —> java语言操作数据库

JDBC本质

其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类

快速入门

步骤

  1. 导入驱动jar包

下载jar包
https://mvnrepository.com/ Mysql connecter java
https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.21

  1. 注册驱动
  2. 获取数据库的链接对象 Connection
  3. 定义sql
  4. 获取执行sql语句的对象 Statement
  5. 执行sql , 接收返回结果
  6. 处理结果
  7. 释放资源

    实现一个操作

    image.pngimage.png
    image.png
    再创建一个空的项目
    image.png
    image.png
    image.pngfinish
    弹出窗口
    image.png
    next
    image.png
    finish -> OK
    创建一个包
    image.png
    为其命名cn.itcast.jdbc
    image.png
    tips: 如果创建出来的不是这样分开的包,点击右上角小齿轮 -> 取消勾选的Compact Middle Package
    image.png
    image.png

包有了之后写类
image.png
image.png
image.png

导入驱动jar包

连接什么数据库就用什么jar包,这里以MySQL为例
mysql-connector-java-8.0.21.jar
image.png
建一个文件夹libs方便管理jar包,因为做项目时有好多jar包
把jar包复制到libs里面,从计算机里面找到jar包,ctrl C复制到libs Ctrl V
弹出:
image.png
image.png
image.pngOK

总结

复制jar包到项目的libs目录下
右键—>add as Library

注册驱动

image.png这里有一个ClassNotFound的异常 Alt+Enter抛出去就可以了
image.png 抛出之后删去ClassNotFoundimage.png

获取数据库的链接对象

image.png

image.png

database输入错误 报错

image.png
Exception in thread “main” java.sql.SQLSyntaxErrorException: Unknown database ‘pet’

地域时间未设置 报错

Exception in thread “main” java.sql.SQLException: The server time zone value ‘�й���׼ʱ��’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the ‘serverTimezone’ configuration property) to use a more specifc time zone value if you want to utilize time zone support.
修改后:
image.png
这是在使用MySQL 8.0以上版本(MySQL连接驱动和版本都是8.0以上)的时候出现的问题错误

  1. package cn.itcast.jdbc;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.Statement;
  5. public class jdbcDemo1 {
  6. public static void main(String[] args) throws Exception {
  7. //导入jar包
  8. //注册驱动
  9. Class.forName("com.mysql.cj.jdbc.Driver");
  10. //获取数据库的链接对象
  11. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myfirsttest?serverTimezone=Asia/Shanghai","root","123456");
  12. //定义sql语句
  13. String sql = "update account set balance = 500 where id = 1";
  14. //获取执行sql的对象Statement
  15. Statement stmt = conn.createStatement();
  16. //执行sql
  17. int count = stmt.executeUpdate(sql);
  18. //处理结果
  19. System.out.println(count);
  20. //释放资源
  21. stmt.close();
  22. conn.close();
  23. }
  24. }
  25. 结果:
  26. 1
  27. Process finished with exit code 0

详解各个对象

  1. DriverManager:驱动管理对象
  2. Connection :数据库连接对象
  3. Statement:执行sql的对象
  4. ResultSet:结果集对象
  5. PreparedStatement:执行sql的对象

    DriverManager

    驱动管理对象
    功能:

    注册驱动:告诉程序该使用哪一个数据库驱动jar包

    static void registerDriver(Driver diver) :注册与给定的驱动程序DiverManager。
    写代码使用:Class.forName(“com.mysql.cj.jdbc.Driver”);
    通过查看源码发现:在com.mysql.cj.jdbc.Driver类中存在静态代码块
    image.png

注释掉后发现程序依旧可以运行,why?
image.png
注释掉后被MySQL5+自动帮忙注册驱动了,所以MySQL5之后的驱动jar包可以省略注册驱动的步骤

获取数据库链接

方法

static Connection getConnection(String url , string user , String password )

参数:

url :指定连接的路径
语法:jdbc : mysql:// ip地址(域名): 端口号 / 数据库名称
🌰: jdbc:mysql:// localhost : 3306 / myfirsttest
细节:如果连接的是本机MySQL服务器,并且MySQL服务默认端口是3360,则url可简写为: jdbc:mysql:///数据库名称
image.png
user:用户名
password:密码

Connection

数据库链接对象

  1. 功能:
    1. 获取执行sql的对象

Statement createStatement():获取一个Statemen对象,用于将sql语句发送到数据库
PreparedStatement preparedStatement(String sql)

  1. 管理事务
    1. 开启事务:setAutoCommit(boolean autoCommit) 调用该方法设置参数为false,即开启事务
    2. 提交事务:commit()
    3. 回滚事务:rollback()

      Statement

      执行SQL的对象
  1. 执行sql
    1. boolean execute(String sql) : 可以执行任意的sql (了解)
    2. int executeUpdate(Strirng sql) : 执行DML(insert update delete)语句、DDL(create alter drop)语句

返回值:影响的行数
image.png影响两行
image.png
可以通过这个影响的行数来判断DML语句是否执行成功 返回值>0,则成功,反之失败
c. ResultSet executeQuery (String sql) : 执行DQL (select)语句,返回一个结果及对象(后面讲

🍕练习:

account表 添加一条记录

注册驱动的时候发现一个异常,抓一下 try/catch一下
image.png
image.png
获取Connection对象时候再抓一个异常
image.png
抓完之后出现一个catch
image.png
释放资源
image.png
因为stmt在try作用域里面,相当于一个局部变量。
此时要提升它的作用域,把它提升到try的外面

  1. package cn.itcast.jdbc;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. /*
  7. * account表 添加一条记录 insert 语句的一个练习
  8. * */
  9. public class JDBCDemo2 {
  10. public static void main(String[] args){
  11. Statement stmt = null;
  12. Connection conn = null;
  13. //不用导入jar包了,可省略
  14. try {
  15. //1. 注册驱动
  16. Class.forName("com.mysql.cj.jdbc.Driver");
  17. //2.定义sql
  18. String sql = "insert into account values(3,'王五','2020-10-01',3000) ";
  19. //3.获取Connection对象
  20. conn = DriverManager.getConnection("jdbc:mysql:///myfirsttest?serverTimezone=Asia/Shanghai","root","123456");
  21. //4.获取执行sql的对象Statement
  22. stmt = conn.createStatement();
  23. //5.执行sql
  24. int count = stmt.executeUpdate(sql); //count 影响的行数
  25. //6.处理结果
  26. System.out.println(count);
  27. if (count>0){
  28. System.out.println("添加成功");
  29. }else {
  30. System.out.println("添加失败");
  31. }
  32. } catch (ClassNotFoundException e) {
  33. e.printStackTrace();
  34. } catch (SQLException e) {
  35. e.printStackTrace();
  36. }finally {
  37. //stmt.close(); 如果中间出错(如:密码错误),那么会返回一个空指针
  38. //7.释放资源
  39. //避免空指针异常
  40. if (stmt != null){
  41. try {
  42. stmt.close();
  43. } catch (SQLException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. //复制粘贴一下 判断conn
  48. if (conn != null){
  49. try {
  50. conn.close();
  51. } catch (SQLException e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. }
  56. }
  57. }
  58. 结果:
  59. 1
  60. 添加成功

account表 修改记录

  1. package cn.itcast.jdbc;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. /*
  7. * account表修改记录 王五金额修改为200
  8. * */
  9. public class JDBCDemo3 {
  10. public static void main(String[] args) {
  11. Connection conn = null;
  12. Statement stmt = null;
  13. try {
  14. //1.注册驱动
  15. Class.forName("com.mysql.cj.jdbc.Driver");
  16. //2.获取连接对象
  17. conn = DriverManager.getConnection("jdbc:mysql:///myfirsttest?serverTimezone=Asia/Shanghai", "root", "123456");
  18. //3.定义sql
  19. String sql = "update account set balance = 200 where id = 3";
  20. //4.获取执行sql对象
  21. stmt = conn.createStatement();
  22. //5.执行sql
  23. int count = stmt.executeUpdate(sql);
  24. //6.处理结果
  25. System.out.println(count);
  26. if (count > 0) {
  27. System.out.println("更新修改成功");
  28. } else {
  29. System.out.println("更新修改失败");
  30. }
  31. } catch (ClassNotFoundException e) {
  32. e.printStackTrace();
  33. } catch (SQLException e) {
  34. e.printStackTrace();
  35. } finally {
  36. //释放资源 防止空指针异常
  37. if (stmt != null) {
  38. try {
  39. stmt.close();
  40. } catch (SQLException e) {
  41. e.printStackTrace();
  42. }
  43. if (conn != null) {
  44. try {
  45. conn.close();
  46. } catch (SQLException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. }
  51. }
  52. }}

account表 删除一套记录

复制上面的代码,改动一下第三步的语句
delete from account where id = 3


ResultSet

结果集对象,封装查询结果
就是把这些结果对象拿出来
游标(类似指针)

image.png

游标默认指向表头(第一行)
此时不能取数据

作用过程涉及两类方法

next()

boolean类型的值,游标从当前位置向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是则返回false,反之true

getXxx(参数)

获取数据
一次获取某一行的某一列的数据
Xxx: 数据类型 eg:int getInt(),String getString()
参数:

  1. 1. Int 代表列的编号,从**1**开始 eggetInt(1)
  2. 1. String:代表列的名称 eggetString("balance")

范例

  1. package cn.itcast.jdbc;
  2. import java.sql.*;
  3. public class JDBCDemo6 {
  4. public static void main(String[] args) {
  5. Connection conn = null;
  6. Statement stmt = null;
  7. ResultSet rs = null;
  8. try {
  9. //1.注册驱动
  10. Class.forName("com.mysql.cj.jdbc.Driver");
  11. //2.获取连接对象
  12. conn = DriverManager.getConnection("jdbc:mysql:///myfirsttest?serverTimezone=Asia/Shanghai", "root", "123456");
  13. //3.定义sql
  14. String sql = "select * from account";
  15. //4.获取执行sql对象
  16. stmt = conn.createStatement();
  17. //5.执行sql
  18. rs = stmt.executeQuery(sql);
  19. //6.处理结果
  20. //6.1让游标向下移动一行
  21. rs.next();
  22. //6.2获取数据
  23. int id = rs.getInt(1);
  24. String name= rs.getString("name");
  25. double balance = rs.getDouble(3);
  26. System.out.println(id+"---"+name+"---"+balance);
  27. } catch (ClassNotFoundException e) {
  28. e.printStackTrace();
  29. } catch (SQLException e) {
  30. e.printStackTrace();
  31. } finally {
  32. //释放资源 防止空指针异常
  33. if (stmt != null) {
  34. try {
  35. stmt.close();
  36. } catch (SQLException e) {
  37. e.printStackTrace();
  38. }
  39. if (rs != null) {
  40. try {
  41. rs.close();
  42. } catch (SQLException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }
  48. }
  49. }
  50. 结果:
  51. 2---ls---2000.0

使用步骤

  1. 游标向下移动一行
  2. 判断是否有数据 : boolean next() 有数据true
  3. 获取数据

    1. while(rs.next()) //循环判断结果集是否有数据
    2. {
    3. //6.2获取数据
    4. int id = rs.getInt(1);
    5. String name= rs.getString("name");
    6. double balance = rs.getDouble(3);
    7. System.out.println(id+"---"+name+"---"+balance);
    8. }

    eg:
    定义一个方法,查询account表的数据,将其封装为对象,然后装载集合,返回。打印

  4. 定义account类

  5. 定义方法 public List findAll(){}
  6. 实现方法 select * from account ;

image.png

  1. package cn.itcast.domain;
  2. //封装account表数据的JavaBean
  3. public class account {
  4. private int id;
  5. private String name;
  6. private double balance;
  7. //右键-->Generate -->Ctrl全选
  8. public int getId() {
  9. return id;
  10. }
  11. public void setId(int id) {
  12. this.id = id;
  13. }
  14. public String getName() {
  15. return name;
  16. }
  17. public void setName(String name) {
  18. this.name = name;
  19. }
  20. public double getBalance() {
  21. return balance;
  22. }
  23. public void setBalance(double balance) {
  24. this.balance = balance;
  25. }
  26. @Override
  27. public String toString() {
  28. return "account{" +
  29. "id=" + id +
  30. ", name='" + name + '\'' +
  31. ", balance=" + balance +
  32. '}';
  33. }
  34. }
  1. package cn.itcast.jdbc;
  2. import cn.itcast.domain.account;
  3. import java.sql.*;
  4. import java.util.*;
  5. /*
  6. * 定义一个方法,查询account表的数据,将其封装为对象,然后装载集合,返回。
  7. * */
  8. public class JDBCDemo8 {
  9. public static void main(String[] args) {
  10. List<account> list = new JDBCDemo8().findAll();
  11. System.out.println(list);
  12. }
  13. //查询所有emp对象
  14. //@return
  15. public List<account> findAll(){
  16. ResultSet re = null;
  17. Statement stmt = null;
  18. Connection conn = null;
  19. List<account> list = null;
  20. try {
  21. //1.注册驱动
  22. Class.forName("com.mysql.cj.jdbc.Driver");
  23. //2.获取链接
  24. conn = DriverManager.getConnection("jdbc:mysql:///myfirsttest?serverTimezone=Asia/Shanghai","root","123456");
  25. //3.定义sql
  26. String sql = "select * from account";
  27. //4.获取执行sql的对象
  28. stmt = conn.createStatement();
  29. //5.执行sql
  30. re = stmt.executeQuery(sql);
  31. //6.遍历结果集,封装对象,装载集合
  32. account ac = null;
  33. list = new ArrayList<account>();
  34. while(re.next()){
  35. //获取数据
  36. int id = re.getInt("id");
  37. String name = re.getString("name");
  38. double balance = re.getDouble("balance");
  39. //创建account对象
  40. ac = new account();
  41. ac.setId(id);
  42. ac.setBalance(balance);
  43. ac.setName(name);
  44. //装载集合
  45. list.add(ac);
  46. }
  47. //list.forEach(System.out::println);
  48. } catch (ClassNotFoundException e) {
  49. e.printStackTrace();
  50. } catch (SQLException e) {
  51. e.printStackTrace();
  52. }finally {
  53. if (re != null){
  54. try {
  55. re.close();
  56. } catch (SQLException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. if (stmt != null){
  61. try {
  62. stmt.close();
  63. } catch (SQLException e) {
  64. e.printStackTrace();
  65. }
  66. }
  67. if (conn != null){
  68. try {
  69. conn.close();
  70. } catch (SQLException e) {
  71. e.printStackTrace();
  72. }
  73. }
  74. }
  75. return list;
  76. }
  77. }

PreparedStatement

Statement的衍生,执行SQL的对象(功能比Statement更强)


抽取JDBC工具类

JDBCUtils

简化书写

分析

  1. 注册驱动也抽取
  2. 抽取一个方法获取连接对象

需求:不想传递参数(麻烦),还得保证工具类的通用性。
解决:配置文件
定义一个jdbc.properties配置文件,
其中记录:
url=
user=
password=

  1. 抽取一个方法释放资源

image.png

  1. package cn.itcast.util;
  2. import java.io.FileReader;
  3. import java.io.IOException;
  4. import java.net.URL;
  5. import java.sql.*;
  6. import java.util.Properties;
  7. //jdbc工具类
  8. public class JDBCUtils {
  9. //声明三个成员变量
  10. private static String url;
  11. private static String user;
  12. private static String password;
  13. private static String driver;
  14. /**
  15. * 文件的读取,只需要读取一次即可拿到这些值.使用静态代码块
  16. */
  17. static{
  18. //读取资源文件,获取值。
  19. try {
  20. //1.创建Properties集合类
  21. Properties pro = new Properties();
  22. //获取src路径下的文件的方式--->ClassLoader 类加载器,加载字节码文件径内存,且获取src下的文件路径
  23. ClassLoader classLoader = JDBCUtils.class.getClassLoader();
  24. URL res = classLoader.getResource("jdbc.properties");
  25. //URL 表示一个统一资源定位符 ↑ 定义了一个文件的绝对路径
  26. String path = res.getPath();
  27. System.out.println(path);
  28. //2.加载文件
  29. // pro里load方法load(Reader字符流 /InputStream字节流)
  30. //pro.load(new FileReader("src/jdbc.properties"));
  31. pro.load(new FileReader(path));
  32. //3.获取属性 赋值
  33. url = pro.getProperty("url");
  34. user = pro.getProperty("user");
  35. password = pro.getProperty("password");
  36. driver = pro.getProperty("driver");
  37. try {
  38. //4.注册驱动
  39. Class.forName(driver);
  40. } catch (ClassNotFoundException e) {
  41. e.printStackTrace();
  42. }
  43. } catch (IOException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. /**
  48. * 获取连接
  49. * @return 连接对象
  50. */
  51. // 工具类有个特点,所有方法都是静态的,方便调用
  52. public static Connection getConnection() throws SQLException {
  53. return DriverManager.getConnection(url,user,password);
  54. }
  55. /**
  56. * 关闭/释放资源方法
  57. * 没有返回值
  58. */
  59. public static void close(Statement stmt, Connection conn){
  60. if (stmt != null){
  61. try {
  62. stmt.close();
  63. } catch (SQLException e) {
  64. e.printStackTrace();
  65. }
  66. }
  67. if (conn != null){
  68. try {
  69. conn.close();
  70. } catch (SQLException e) {
  71. e.printStackTrace();
  72. }
  73. }
  74. }
  75. public static void close(ResultSet rs , Statement stmt, Connection conn){
  76. if (rs != null){
  77. try {
  78. rs.close();
  79. } catch (SQLException e) {
  80. e.printStackTrace();
  81. }
  82. }
  83. if (stmt != null){
  84. try {
  85. stmt.close();
  86. } catch (SQLException e) {
  87. e.printStackTrace();
  88. }
  89. }
  90. if (conn != null){
  91. try {
  92. conn.close();
  93. } catch (SQLException e) {
  94. e.printStackTrace();
  95. }
  96. }
  97. }
  98. }

image.png

  1. url = jdbc:mysql:///myfirsttest?serverTimezone=Asia/Shanghai
  2. user = root
  3. password = 123456
  4. driver = com.mysql.cj.jdbc.Driver

演示JDBC工具类

  1. package cn.itcast.jdbc;
  2. import cn.itcast.domain.account;
  3. import cn.itcast.util.JDBCUtils;
  4. import java.sql.*;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. public class JDBCDemo8_1 {
  8. public static void main(String[] args) {
  9. List<account> list = new JDBCDemo8_1().findAll2();
  10. System.out.println(list);
  11. }
  12. //演示JDBC工具类
  13. //@return
  14. public List<account> findAll2() {
  15. ResultSet re = null;
  16. Statement stmt = null;
  17. Connection conn = null;
  18. List<account> list = null;
  19. try {
  20. // //1.注册驱动
  21. // Class.forName("com.mysql.cj.jdbc.Driver");
  22. // //2.获取链接
  23. // conn = DriverManager.getConnection("jdbc:mysql:///myfirsttest?serverTimezone=Asia/Shanghai","root","123456");
  24. conn = JDBCUtils.getConnection();
  25. //3.定义sql
  26. String sql = "select * from account";
  27. //4.获取执行sql的对象
  28. stmt = conn.createStatement();
  29. //5.执行sql
  30. re = stmt.executeQuery(sql);
  31. //6.遍历结果集,封装对象,装载集合
  32. account ac = null;
  33. list = new ArrayList<account>();
  34. while (re.next()) {
  35. //获取数据
  36. int id = re.getInt("id");
  37. String name = re.getString("name");
  38. double balance = re.getDouble("balance");
  39. //创建account对象
  40. ac = new account();
  41. ac.setId(id);
  42. ac.setBalance(balance);
  43. ac.setName(name);
  44. //装载集合
  45. list.add(ac);
  46. }
  47. //list.forEach(System.out::println);
  48. } catch (SQLException e) {
  49. e.printStackTrace();
  50. }finally {
  51. // if (re != null){
  52. // try {
  53. // re.close();
  54. // } catch (SQLException e) {
  55. // e.printStackTrace();
  56. // }
  57. // }
  58. // if (stmt != null){
  59. // try {
  60. // stmt.close();
  61. // } catch (SQLException e) {
  62. // e.printStackTrace();
  63. // }
  64. // }
  65. // if (conn != null){
  66. // try {
  67. // conn.close();
  68. // } catch (SQLException e) {
  69. // e.printStackTrace();
  70. // }
  71. // }
  72. // }
  73. JDBCUtils.close(re, stmt, conn);
  74. return list;
  75. }
  76. }
  77. }

🍕练习

需求:

  1. 通过键盘录入用户名和密码
  2. 判断用户是否登录成功

select * from user where username = "" and password = "" ;
如果这个sql语句有查询结果,则成功。否则失败。

步骤:

  1. 创建数据表 user

image.pngimage.png

  1. package cn.itcast.jdbc;
  2. import cn.itcast.util.JDBCUtils;
  3. import com.sun.org.apache.bcel.internal.generic.Select;
  4. import java.sql.Connection;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. import java.sql.Statement;
  8. import java.util.Scanner;
  9. /**
  10. * 需求:
  11. * 1. 通过键盘录入用户名和密码
  12. * 2. 判断用户是否登录成功
  13. */
  14. public class JDBCDemo9 {
  15. public static void main(String[] args) {
  16. //1.键盘录入,接受用户名和密码
  17. Scanner sc = new Scanner(System.in);
  18. System.out.println("username:");
  19. String username = sc.nextLine();
  20. System.out.println("password:");
  21. String password = sc.nextLine();
  22. //2.调用方法
  23. boolean flag = new JDBCDemo9().login(username,password);
  24. //3.判断结果,输出不同语句
  25. if (flag){
  26. //登陆成功
  27. System.out.println("登陆成功!");
  28. }else {
  29. System.out.println("用户名或密码错误!");
  30. }
  31. }
  32. /**
  33. * 登陆方法
  34. */
  35. public boolean login(String username,String password){
  36. if (username == null || password == null){
  37. return false;
  38. }
  39. //连接数据库判断是否登录成功
  40. Connection conn = null;
  41. Statement stmt= null;
  42. ResultSet re= null;
  43. //1.获取连接
  44. try {
  45. conn = JDBCUtils.getConnection();
  46. //2.定义sql
  47. String sql = "select * from user where username = '"+username+"' and password = '"+password+"'";
  48. //3.获取执行sql对象
  49. stmt = conn.createStatement();
  50. //执行查询
  51. re = stmt.executeQuery(sql);
  52. //5.判断
  53. return re.next();//如果有下一行,返回true
  54. } catch (SQLException e) {
  55. e.printStackTrace();
  56. }finally {
  57. JDBCUtils.close(re,stmt,conn);
  58. }
  59. return false;
  60. }
  61. }

sql注入问题:、

在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性的问题。
🌰随便输入username,然后输入password:a’ or ‘a’ = ‘a ,却登陆成功
image.png

如何解决?

使用 PreparedStatement 对象来解决
预编译的sql:参数使用 ? 作为占位符
步骤:

  1. 导入驱动jar包
  2. 注册驱动
  3. 获取数据库的链接对象 Connection
  4. 定义sql
    • 注意:sql参数使用?作为占位符
      • 🌰: select * from user where username = ? and password = ? ;
  5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
  6. 给“?”赋值
    • 方法:`setXxx(参数1 , 参数2)
      • 参数1:?的位置编号 从1开始
      • 参数2:?的值
  7. 执行sql , 接收返回结果
  8. 处理结果
  9. 释放资源

    🧐tip

    后期都会使用PreparedStatement来完成增删改查的所有操作
    它可以防止sql注入问题
    效率更高

    事务

    一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

    操作

  10. 开启事务

  11. 提交事务
  12. 回滚事务

    使用Connection

  • 开启事务:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
    • 在执行sql之前开启事务
  • 提交事务:commit()
    • 当所有sql都执行完提交事务
  • 回滚事务:rollback()
    • 在catch中回滚事务 ```java package cn.itcast.jdbc;

import cn.itcast.util.JDBCUtils; import com.mysql.cj.x.protobuf.MysqlxCrud;

import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException;

/**

  • 事务操作 */ public class JDBCDemo10 { public static void main(String[] args) {

    1. Connection conn = null;
    2. PreparedStatement pstm1 = null;
    3. PreparedStatement pstm2 = null;
    4. try {
    5. //1.获取连接
    6. conn = JDBCUtils.getConnection();
    7. //开启事务
    8. conn.setAutoCommit(false);
    9. //2.定义sql
    10. //2.1 张三 -500
    11. String sql1 = "update account set balance = balance - ? where id = ?";
    12. //2.2 李四 +500
    13. String sql2 = "update account set balance = balance + ? where id = ?";
    14. //3.获取执行sql对象
    15. pstm1 = conn.prepareStatement(sql1);
    16. pstm2 = conn.prepareStatement(sql2);
    17. //4.设置参数
    18. pstm1.setDouble(1,500);
    19. pstm1.setInt(2,1);
    20. pstm2.setDouble(1,500);
    21. pstm2.setInt(2,2);
    22. //5.执行sql
  1. // 手动制造异常
  2. int i = 3/0;
  3. pstm1.executeUpdate();
  4. pstm2.executeUpdate();
  5. //提交事务
  6. conn.commit();
  7. } catch (Exception e) { //事务回滚时候抓大一点的异常
  8. //事务回滚
  9. try {
  10. if (conn!=null){ //conn有可能为null
  11. conn.rollback();
  12. }
  13. } catch (SQLException ex) {
  14. ex.printStackTrace();
  15. }
  16. e.printStackTrace();
  17. }finally {
  18. JDBCUtils.close(pstm1,conn);
  19. JDBCUtils.close(pstm2,null);
  20. }
  21. }

}

``` account表没有变化