网友整理老杜2020版本JDBC:
https://blog.csdn.net/qq_32480989/article/details/120876779
JDBC 基础概念
JDBC是什么?
Java DataBase Connectivity( Java语言连接数据库)
JDBC的本质是什么?
JDBC是SUN公司制定的一套接口(interface),java.sql.*; (这个软件包下有很多接口。)
接口都有调用者和实现者。
面向接口调用、面向接口写实现类,这都属于面向接口编程。为什么要面向接口编程?
**解耦合:降低程序的耦合度,提高程序的扩展力。**<br /> 多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)<br /> 建议:
Animal a = new Cat();Animal a = new Dog();// 喂养的方法public void feed(Animal a){ // 面向父类型编程。}不建议:Dog d = new Dog();Cat c = new Cat();
思考:为什么SUN制定一套JDBC接口呢?
因为每一个数据库的底层实现原理都不一样,Oracle数据库有自己的原理,MySQL数据库也有自己的原理,每一个数据库产品都有自己独特的实现原理。<br />
JDBC的本质到底是什么?
**一套接口**
JDBC 开发流程
开发流程
JDBC开发前的准备工作,先从官网下载对应的驱动jar包,然后将其配置到环境变量 classpath当中
classpath=.;D:\course\06-JDBC\resources\MySql Connector Java 5.1.23\mysql-connector-java-5.1.23-bin.jar
注意:
- .;表示任意路径
- 以上的配置是针对于文本编辑器的方式开发,使用IDEA工具的时候,不需要配置以上的环境变量
- IDEA有自己的配置方式。
JDBC编程六步(需要背会)
第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行SQL语句(DQL DML….)
第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)
模拟JDBC的本质




- JDBC的本质

JDBC 课堂测试源码
- java.SQL包下:
- java 中 sql 源码路径:
java帮助文档——>java.SQL包下———->类、接口
复习:除了java.lang包,其余包都需要导包
- JDBC开发的步骤详细说明:
- 第一步:注册驱动
有一个类 :DriverManager 驱动管理器 Driver 的意思是驱动
里面有一个方法:static void registerDriver( Driver driver) 注册驱动的方法
这个方法的参数的说明:Driver是一个接口 无法new对象,就得找Driver的实现类,这个实现类是有数据库厂商写的,得去new产商写的那个实现类Driver
格式:new 包名.类名();
说明:厂商的实现类是公开的,需要包名.方式去访问这个实现类,然后再创建这个类的对象,去厂商的jar包找这个实现类。
- 这个方法的异常说明:

说明:继承了 exception 说明了 是受检异常,需要处理,
- 第二步:获取连接
url:统一资源定位符(网络中某个资源的绝对路径)
https://www.baidu.com/ 这就是URL。
URL包括哪几部分?
协议
IP
PORT
资源名
[http://182.61.200.7:80/index.html](http://182.61.200.7:80/index.html)<br /> http:// 通信协议<br /> 182.61.200.7 服务器IP地址<br /> 80 服务器上软件的端口<br /> index.html 是服务器上某个资源名<br /> <br /> <br /> **jdbc:mysql://127.0.0.1:3306/bjpowernode**<br /> jdbc:mysql:// 协议<br /> 127.0.0.1 IP地址<br /> 3306 mysql数据库端口号<br /> bjpowernode 具体的数据库实例名。<br /> <br /> 说明:localhost和127.0.0.1都是本机IP地址。jdbc:mysql://192.168.151.27:3306/bjpowernode<br />
什么是通信协议,有什么用?
通信协议是通信之前就提前定好的数据传送格式。<br /> 数据包具体怎么传数据,格式提前定好的。<br />
oracle的URL:
jdbc:oracle:thin:@localhost:1521:orcl
- JDBCTest01源码
编程六步:
import java.sql.Driver;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Connection;import java.sql.Statement;public class JDBCTest01{public static void main(String[] args){Connection conn = null;Statement stmt = null;try{//1、注册驱动Driver driver = new com.mysql.jdbc.Driver(); // 多态,父类型引用指向子类型对象。// Driver driver = new oracle.jdbc.driver.OracleDriver(); // oracle的驱动。DriverManager.registerDriver(driver);//2、获取连接String url = "jdbc:mysql://192.168.151.9:3306/bjpowernode";String user = "root";String password = "981127";conn = DriverManager.getConnection(url,user,password);// com.mysql.jdbc.JDBC4Connection@41cf53f9System.out.println("数据库连接对象 = " + conn);//3、获取数据库操作对象(Statement专门执行sql语句的)stmt = conn.createStatement();//4、执行sqlString sql = "insert into dept(deptno,dname,loc) values(50,'人事部','北京')";// 专门执行DML语句的(insert delete update)// 返回值是“影响数据库中的记录条数”int count = stmt.executeUpdate(sql);System.out.println(count == 1 ? "保存成功" : "保存失败");//5、处理查询结果集}catch(SQLException e){e.printStackTrace();}finally{//6、释放资源// 为了保证资源一定释放,在finally语句块中关闭资源// 并且要遵循从小到大依次关闭// 分别对其try..catchtry{if(stmt != null){stmt.close();}}catch(SQLException e){e.printStackTrace();}try{if(conn != null){conn.close();}}catch(SQLException e){e.printStackTrace();}}}}
JDBC完成 delete、updata
学习方法:下去背代码
JDBCtest02
注册驱动的另一种方式
- JDBCTest03 ```java import java.sql.*;
public class JDBCTest03{ public static void main(String[] args){ try{ //1、注册驱动 // 这是注册驱动的第一种写法。 // DriverManager.registerDriver(new com.mysql.jdbc.Driver()); // 注册驱动的第二种方式:常用的。 // 为什么这种方式常用?因为参数是一个字符串,字符串可以写到xxx.properties文件中。 // 以下方法不需要接收返回值,因为我们只想用它的类加载动作。 Class.forName(“com.mysql.jdbc.Driver”); //反射机制进行类加载 //Class.forName()方法的执行会导致,方法里面的类进行类加载,然后静态代码块执行,完成驱动的注册 //2、获取连接 Connection conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/bjpowernode”,”root”,”333”); // com.mysql.jdbc.JDBC4Connection@41cf53f9 System.out.println(conn);
}catch(SQLException e){e.printStackTrace();}catch(ClassNotFoundException e){e.printStackTrace();}}
}
**将连接数据库的所有信息配置到配置文件当中**<a name="x5Voq"></a>## 从属性资源文件中读取连接数据库信息Test04```javadriver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/bjpowernodeuser=rootpassword=123456
配置文件:jdbc.properties
package jdbc;import java.sql.*;import java.util.ResourceBundle;/*实际开发中不建议把连接数据库的信息写死在java程序中。*/public class jdbc04 {public static void main(String[] args) {// 使用资源绑定器绑定属性配置文件ResourceBundle bundle =ResourceBundle.getBundle("jdbcc");String driver=bundle.getString("key");String url=bundle.getString("url");String user=bundle.getString("user");String password=bundle.getString("password");Connection conn=null;Statement stmt=null;try {//1、注册驱动(只需要改这个)Class.forName(driver);//2、获取连接conn = DriverManager.getConnection(url,user,password);//3、获取数据库操作对象stmt=conn.createStatement();////4、执行sqlString sql="update dept set dname='销售部2',loc='天津'where deptno=20";int count=stmt.executeUpdate(sql);System.out.println(count==1?"修改成功":"修改失败");} catch (SQLException e) {e.printStackTrace();}catch (ClassNotFoundException e) {e.printStackTrace();}finally{//6、释放资源if(stmt!=null){try{stmt.close();}catch(SQLException e){e.printStackTrace();}}if(conn!=null){try{conn.close();}catch(SQLException e){e.printStackTrace();}}}}}
处理查询结果集
笔记: 查询完的结果封装在 ResultSet里面
Test05
package jdbc;import javax.swing.*;import java.sql.*;/*处理查询结果集*/public class jdbc05 {public static void main(String[] args) {Connection conn=null;Statement stmt=null;ResultSet rs=null;try {//1、注册驱动DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());//2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode","root","123456");//3、获取数据库操作对象stmt=conn.createStatement();////4、执行sqlString sql="select empno,ename,sal from emp";//ResultSet executeQuery(String sql) throws SQLEXception//执行给定的SQL语句,该语句返回单词ResultSet对象。// 参数sql 为要发送给数据库的SQL语句,通常为静态SQL select语句。//int executeUpdate(insert/delete/update)//ResultSet executeQuery(select)//ResultSet是执行sql语句后的查询结果集rs=stmt.executeQuery(sql);//5、处理查询结构集/*理解过程boolean flag1=rs.next();//本来在第0行,现在next到了第一行,如果有数据就返回true// System.out.println(flag1); //trueif(flag1){//光标指向的行有数据//取数据//getString()方法的特点是:不管数据库中的数据类型是什么,都以String的形式取出String empno=rs.getString(1);//跟的是下标,第一列,第二列,第三列String ename=rs.getString(2);//jdbc中所有的下标从1开始,不是从0开始的String sal=rs.getString(3);System.out.println(empno+","+ename+","+sal);}//rs.next();//boolean next() throws SQLException将光标从当前位置向前移一行。// ResultSet 光标最初位于第一行之前;第一次调用 next// 方法使第一行成为当前行;第二次调用使第二行成为当前行,依此类推。// 返回:如果新的当前行有效,则返回 true;如果不存在下一行,则返回 false//抛出:SQLException - 如果发生数据库访问错误或在关闭的结果集上调用此方法*/while(rs.next()){/*String empno=rs.getString(1);String ename=rs.getString(2);String sal=rs.getString(3);System.out.println(empno+","+ename+","+sal);*//*另一种写法,不是以列的下标获取,以列的名字获取String empno=rs.getString("empno");String ename=rs.getString("ename");String sal=rs.getString("sal");System.out.println(empno+","+ename+","+sal);*/int empno=rs.getInt(1);//之所以这能用int 是因为底层数据是int类型的,不然要以String类型String ename=rs.getString(2);double sal=rs.getDouble(3);System.out.println(empno+","+ename+","+(sal-100));//double类型 方便进行运算}} catch (SQLException e) {e.printStackTrace();}finally{//6、释放资源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();}}}}}
ResultSet rs 存的是执行sql语句后的查询结果集
遍历结果集:
IDEA工具开发JDBC
将JDBC的jar包导入idea步骤
- 第一种方式:
- 打开模块设置

- 鼠标点的这个英文单词为库

- 添加Java库,选择 JDBC.jar 包路径 导入
说明:如果建立新的模块需要将,jar包重新导入
第二种方式:
在需要导入的模块,建立目录,然后将JDBC的jar包粘贴到此目录
第二步:将jar包,加入到这个模块就行

快捷键
- ctrl +shift+F12
- ifn
idea中第一个JDBC程序
数据库表的设计阶段
- PowerDesigner 数据库表设计 工具的安装
作用:物理建模的,系统设计时用 PowerDesigner 工具
- 将激活文件到安装目录进行,替换
- 使用步骤:

快捷键:按住ctrl键+鼠标滑轮,就可以看见很多单元格
双击新建的表,在新的窗口进行设计
小项目
需求:模拟用户登录功能的实现
描述:
开发经验:能抽象成一个方法的最好抽象成一个方法
SQL注入问题
JDBCTest06 存在SQL注入问题
package jdbc;import java.sql.*;import java.util.HashMap;import java.util.Map;import java.util.Scanner;public class jdbc06 {public static void main(String[] args) {//初始化一个界面,可以让用户输入用户名和密码Map<String,String>userLoginInfo=initUI();//连接数据库验证用户和密码是否正确boolean ok=checkNameAndPwd(userLoginInfo.get("loginName"),userLoginInfo.get("loginPwd"));System.out.println(ok?"登陆成功":"登陆失败");}private static boolean checkNameAndPwd(String loginName, String loginPwd) {boolean ok=false;//默认登录是失败的,Connection conn = null;Statement stmt = null;ResultSet rs = null;// 1、注册驱动try {Class.forName("com.mysql.cj.jdbc.Driver");// 2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");// 3、获取数据库操作对象stmt = conn.createStatement();// 4、执行sql语句String sql = "select * from t_user where login_name='"+loginName+"'and login_pwd='"+loginPwd+"'";System.out.println(sql);//程序执行到此处,才会将以上的sql语句发送到DBMS上,DBMS进行sql语句的编译。rs = stmt.executeQuery(sql);//sql处理后会返回一个处理集,//如果以上sql语句中用户名和密码是正确的,那么结果集最多也就查询出一条记录,所以以下不需要while循环。if就够了if(rs.next()){//此条件如果成立,表示登录成功ok=true;}// 5、处理结果集} catch (Exception e) {e.printStackTrace();}finally {// 6、释放资源if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (stmt != null) {try {stmt.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn!= null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return ok;}private static Map<String, String> initUI(){System.out.println("欢迎使用该系统,请输入用户名和密码进行身份认证");Scanner s=new Scanner(System.in);System.out.println("用户名:");String loginName=s.nextLine();System.out.println("密码:");String loginPwd=s.nextLine();//将用户名和密码放在map集合中Map<String,String> useLoginInfo=new HashMap<>();useLoginInfo.put("loginName",loginName);useLoginInfo.put("loginPwd",loginPwd);//返回mapreturn useLoginInfo;}/*随便输入一个用户名的密码,登录成功了,这种现象被称为SQL注入现象!导致SQL注入的根本原因是:用户不是一般的用户,用户是懂程序的,输入的用户名信息以及密码信息中,含有SQL语句的关键词,这个SQL语句的关键字和底层的SQL语句进行“字符串拼接”,导致原SQL语句的含义被扭曲了。最最主要的原因是:用户提供的信息参与了SQL语句的编译。主要因素,这个程序是先进行字符串的拼接,然后再进行sql语句的编译,正好彼注入。用户名:fdsa密码:fdsa' or '1'='1select * from t_user where login_name='fdsa'and login_pwd='fdsa' or '1'='1'*/}
解决SQL注入问题(重点学习)
JDBCTest07
package jdbc;import java.sql.*;import java.util.HashMap;import java.util.Map;import java.util.Scanner;/*怎么避免sql注入?sql注入的根本原因是,先进行了字符串的拼接,然后在进行的编译。java.sql.Statement接口的特点,先进行字符串的拼接。然后再进行sql语句的编译。优点:使用Statement可以进行sql语句的拼接。缺点:因为拼接的存在,导致可能给不法分子机会。java.sql.PreparedStatement接口的特点,先进行sql语句的编译,然后在进行sql语句的传值。优点:避免sql注入。缺点:没有办法进行sql语句的拼接,只能给sql语句传值。PreparedStatement预编译的数据库操作对象*/public class jdbc07 {public static void main(String[] args) {//初始化一个界面,可以让用户输入用户名和密码Map<String,String>userLoginInfo=initUI();//连接数据库验证用户和密码是否正确boolean ok=checkNameAndPwd(userLoginInfo.get("loginName"),userLoginInfo.get("loginPwd"));System.out.println(ok?"登陆成功":"登陆失败");}private static boolean checkNameAndPwd(String loginName, String loginPwd) {boolean ok=false;//默认登录是失败的,Connection conn = null;PreparedStatement stmt = null;ResultSet rs = null;// 1、注册驱动try {Class.forName("com.mysql.cj.jdbc.Driver");// 2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");// 3、获取预编译的数据库操作对象//一个问号是一个占位符,一个占位符只能接收一个值/数据String sql = "select * from t_user where login_name=? and login_pwd=?";stmt=conn.prepareStatement(sql);//此时会发送sql给DBMS,进行sql语句的编译//给占位符?传值//怎么解决sql注入的?即使用户信息中有sql关键字,但是不参加编译就没事。//stmt.setInt(1,100);//这样必须是填数字,↓下面那个必须填字符串。stmt.setString(1,loginName);//给第一个占位符传值stmt.setString(2,loginPwd);//给第二个占位符传值// 4、执行sql语句rs = stmt.executeQuery();//这个方法不需要将sql语句传递进去,不能是这样:rs = stmt.executeQuery(sql);因为上面已经把sql传过去了。if(rs.next()){//此条件如果成立,表示登录成功ok=true;}// 5、处理结果集} catch (Exception e) {e.printStackTrace();}finally {// 6、释放资源if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (stmt != null) {try {stmt.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn!= null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return ok;}private static Map<String, String> initUI(){System.out.println("欢迎使用该系统,请输入用户名和密码进行身份认证");Scanner s=new Scanner(System.in);System.out.println("用户名:");String loginName=s.nextLine();System.out.println("密码:");String loginPwd=s.nextLine();//将用户名和密码放在map集合中Map<String,String> useLoginInfo=new HashMap<>();useLoginInfo.put("loginName",loginName);useLoginInfo.put("loginPwd",loginPwd);//返回mapreturn useLoginInfo;}}
一个 ? 表示一个占位符
规律:就是第三步写好SQL语句,用占位符,然后给占位符传值
知识点的补充:当写第一个SQL语句时,会编译然后执行,若你后面在写一模一样的SQL语句就不会编译,直接执行。
Statement使用场景
JDBCTest8 必须使用SQL注入
先使用PreparedStatement-
这个程序输入desc或者asc会出错,因为
select ename,sal from emp order by sal ?会被换成select ename,sal from emp order by sal ‘desc’而不是select ename,sal from emp order by sal desc ,
PreparedStatement比较适合传值,Statement比较适合进行字符串的拼接。
京东升降序那不让用户输入,就是不给你注入的机会。
package jdbc;import java.sql.*;import java.util.Scanner;/**需求:用户再控制台上输入desc则降序,输入asc则升序。*思考以下,这个应该选择Statement还是PreparedStatement选Statement,y因为PreparedStatement只能传值,不能进行sql语句的拼接。*/public class jdbc08 {public static void main(String[] args){Scanner s=new Scanner(System.in);System.out.print("请输入desc或asc[desc是表示降序,asc表示升序]:");//用户输入的String orderKey=s.next();//先使用PreparedStatementConnection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {//1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");//3、获取预编译的数据库操作对象String sql="select ename,sal from emp order by sal ?";ps=conn.prepareStatement(sql);//给?传值ps.setString(1,orderKey);//4、执行sql语句rs=ps.executeQuery();while(rs.next()){String ename=rs.getString("ename");String sal=rs.getString("sal");System.out.println(ename+","+sal);}} catch (Exception e) {e.printStackTrace();}finally {if(rs!=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if(ps!=null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}}
JDBCTest09
再使用statement,此时可以执行了
package jdbc;import java.sql.*;import java.util.Scanner;/**需求:用户再控制台上输入desc则降序,输入asc则升序。*思考以下,这个应该选择Statement还是PreparedStatement*/public class jdbc09 {public static void main(String[] args){Scanner s=new Scanner(System.in);System.out.print("请输入desc或asc[desc是表示降序,asc表示升序]:");//用户输入的String orderKey=s.next();//再使用StatementConnection conn = null;Statement stmt = null;ResultSet rs = null;try {//1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");//3、获取数据库操作对象stmt = conn.createStatement();//4、执行sql语句String sql="select ename,sal from emp order by sal "+orderKey;rs=stmt.executeQuery(sql);while(rs.next()){String ename=rs.getString("ename");String sal=rs.getString("sal");System.out.println(ename+","+sal);}} catch (Exception 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();}}}}}
使用PreparedStatement完成增删改
package jdbc;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException;public class jdbc10 {public static void main(String[] args) {Connection conn=null;PreparedStatement ps=null;try {//1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");//3、获取预编译的数据库操作对象//增加操作/*String sql="insert into dept(deptno,dname,loc) values(?,?,?)";ps=conn.prepareStatement(sql);//给?传值ps.setInt(1,50);ps.setString(2,"销售部");ps.setString(3,"天津");*///更新操作/* String sql="update dept set dname=?,loc=? where deptno = ?";ps=conn.prepareStatement(sql);ps.setString(1,"软件研发部");ps.setString(2,"北京");ps.setInt(3,50);*///删除操作String sql="delete from dept where deptno = ?";ps=conn.prepareStatement(sql);ps.setInt(1,50);// 4、执行sqlint count=ps.executeUpdate();System.out.println(count);} catch (Exception e) {e.printStackTrace();}finally {//6、释放资源if(ps!=null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}}
模糊查询
package jdbc;import java.sql.*;public class jdbc11 {public static void main(String[] args) {Connection conn=null;PreparedStatement ps=null;ResultSet rs=null;try {//1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");//3、获取预编译的数据库操作对象//找出名字中含有O的//以下第一种方法是错误的,因为?不能放在单引号内/*String sql="select ename from emp where ename like '%?%'";ps=conn.prepareStatement(sql);ps.setString(1, "O");*/String sql="select ename from emp where ename like ?";ps=conn.prepareStatement(sql);ps.setString(1, "%O%");// 4、执行sqlrs=ps.executeQuery();while (rs.next()){System.out.println(rs.getString("ename"));}} catch (Exception e) {e.printStackTrace();}finally {//6、释放资源if(ps!=null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}if(ps!=null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}}}}
JDBC 里面的事务
JDBCTest10 测试JDBC里面的事务自动提交【需要手动关掉自动提交】
JDBCTest11 账户转账演示事务【JDBC的事务控制,基于单机事务】
知识点补充:有效数字,从左边起,不为0的数字为有效数字
快捷键补充:ait+shift+inster 可以复制前面不带 * 号的内容 也可以批量编辑
如果程序在执行过程中,有异常,就得手动回滚,保证数据的安全性
JDBC工具类的封装
外部文件
driver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/bjpowernodeuser=rootpassword=123456
封装类 ```css package jdbc.utils; //在一个没有结束的程序中,DBUtil这个类只加载一次
import java.sql.*; import java.util.ResourceBundle;
/ 数据库工具类,便于JDBC的代码编写 / public class DBUtil { //静态变量和静态代码块的执行时候是一样的,先出现的先执行 //构造方法私有化是为了防止new对象,为什么要防止用对象? //因为工具类中的方法都是静态的,不需要new对象,直接用“类名.”的方式调用 private DBUtil(){};//工具类的构造方法私有化的 //类加载时绑定属性资源文件 private static ResourceBundle bundle=ResourceBundle.getBundle(“jdbcc”);
//保证注册驱动在类加载的时执行且只执行一次,则使用静态代码块
static{ try { Class.forName(bundle.getString(“driver”)); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
//获得数据库连接对象public static Connection getConnection() throws SQLException {String url=bundle.getString("url");String user=bundle.getString("user");String password=bundle.getString("password");Connection conn=DriverManager.getConnection(url,user,password);return conn;}/*** 释放资源* conn 连接对象* stmt 数据库操作对象* rs 查询结果集*/public static void close(Connection conn, Statement stmt,ResultSet rs){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();}}}
}
测试类```csspackage jdbc;import java.sql.*;public class jdbc11 {public static void main(String[] args) {Connection conn=null;PreparedStatement ps=null;ResultSet rs=null;try {//1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//2、获取连接conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");//3、获取预编译的数据库操作对象//找出名字中含有O的//以下第一种方法是错误的,因为?不能放在单引号内/*String sql="select ename from emp where ename like '%?%'";ps=conn.prepareStatement(sql);ps.setString(1, "O");*/String sql="select ename from emp where ename like ?";ps=conn.prepareStatement(sql);ps.setString(1, "%O%");// 4、执行sqlrs=ps.executeQuery();while (rs.next()){System.out.println(rs.getString("ename"));}} catch (Exception e) {e.printStackTrace();}finally {//6、释放资源if(ps!=null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}if(ps!=null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}}}}
JDBC 里面的行级锁
1.行级锁的理解:
在 select 语句后面添加了 for update 就表示 emp 表 中工作岗位等于 MANAGER 的行级记录谁都不能动,这叫行级锁
当前事务没有结束的时候,表中那三行记录,就不能动,其它事务无法对着三行记录,进行操作。
行级锁,又被称为悲观锁
关于DQL语句的悲观锁
对于一个DQL语句来说,末尾是可以添加这样一个关键字的:for update
select ename,sal from emp where job=‘MANAGER’ for update ;
以上sql语句的含义是:
在本次事务的执行过程中,job=’MANAGER’的记录被查询,
这些记录在我查询的过程中,任何人,任何事务都不能对
这些记录进行修改操作,直到我当前事务结束。
这种机制被称为:行级锁机制(又叫做悲观锁!)
在mysql中是这样的,
当使用select…where…for updare…时,mysql进行row lock(行锁)还是table lock(表锁)只取决于是否能使用索引(例如主键,unique字段),能则为行锁,否则为表锁:
未查到数据则无锁,而使用’<>’,’like’等操作时,索引会失效,自然进行的是table lock。
所以慎用for update。
整个表锁住的时候会导致性能性能降低,谨慎使用。
使用for update的时候,最好是锁主键值,或者具有unique约束的字段,
锁别的字段可能会导致整个表锁住
逛敲逛练,不用 idea 开发工具,手写出JDBC开发的六步,熟练掌握JDBC里面的代码
挑选一道作业题写到 Java 语句里面
