2022/2/28
一、JDBC基本概念
1.概念:Java DataBase Connectivity Java数据库连接,Java语言操作数据库
2.JDBC本质:其实是官方定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
二、快速入门
package ln.javatest.day01.demo01; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; /* JDBC快速入门 步骤: 1.导入驱动jar包 1.复制jar包到项目的自己创建的文件夹下 2.右击文件夹--> add as 自己创建的文件夹 2.注册驱动 3.获取数据库连接对象Connection 4.定义sql 5.获取执行sql语句的对象Statement 6.执行sql,接收返回结果 7.处理结果 8.要释放获取的资源 */ public class jdbcDemo01 { public static void main(String[] args) throws Exception { //导入驱动包 //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //获取数据库连接对象 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "123456"); // Connection conn = DriverManager.getConnection("jdbc:mysql:///db1", "root", "123456"); //本地主机和端口号也可以省略不写 //定义sql语句 String sql = "update student set age = 22 where id = 1"; //获取执行sql的对象,Statement Statement stmt = conn.createStatement(); //执行sql int count = stmt.executeUpdate(sql); //处理结果 System.out.println(count); //释放获取的对象的资源 stmt.close(); conn.close(); } }
三、对JDBC中各个接口和类详解
1.DriverManager:驱动管理对象
功能:
1)注册驱动:告诉程序该使用哪一个数据库驱动jar
static void registerDriver(Driver driver):注册与给定的驱动程序 DriverManager
写代码使用:Class.forName("com.mysql.jdbc.Driver");
通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
静态代码块特点:当第一次使用本类时,静态代码块执行唯一的一次。
静态内容总是优先于非静态,所以静态代码块比构造方法优先执行。
注意:mysql5之后的驱动jar包可以省略注册驱动的步骤,他自带有。
2)获取数据库连接
1.1方法:static Connection getConnection(String ur1,String user,String password)
1.2参数:
1)ur1:指定连接的路径
1.语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
例子:dbc:mysql:///db1
细节:如果连接的是本地mysql服务器,且服务器的默认端口是3306
可简写为jdbc:mysql:///数据库名称
2.user:用户名
3.password:密码
2.Connection:数据库连接对象
功能:
1.获取执行sql1的对象:
Statement createStatement()
PreparedStatement preparedStatement(String sql)
2.管理实务:
1)开启事务:setAutoCommit(boolean sutoCommit)
调用该方法设置参数为false,即开启事务
2)提交事务:commit()
3)回滚事务:rollback()
3.Statement:执行sql的对象
1.执行sql
1)boolean execute(String sql):可以任意执行的sql
2)int executeUppdate(String sql):执行DML(insert,update,delete)语句、
DDL(create,alter,drop)语句
返回值:影响的行数,可以通过这个判断DML语句是否执行成功
3)ResultSet executeQuery(String sql):执行DQL(Select)语句
案例练习:
package ln.javatest.day01.demo01; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; //student表,添加一条记录insert语句 public class JDBCDemo02 { public static void main(String[] args) { Connection conn = null; Statement stmt = null; try { //1.驱动注册 Class.forName("com.mysql.jdbc.Driver"); //2.定义sql String sql = "insert into student(id,namee,sorce,sex,age) values(4,'张三',98,'nan',25)"; //3.获取Connection对象 conn = DriverManager.getConnection("jdbc:mysql:///db1","root","123456"); //4.获取执行sql的对象Statement stmt = conn.createStatement(); //5.执行sql int count = stmt.executeUpdate(sql); //count是影响的行数 //6.处理结果 System.out.println(count); if(count>0){ System.out.println("添加成功!"); }else{ System.out.println("添加失败 !"); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ if(stmt != null){ try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } }
package ln.javatest.day01.demo01; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; //student表,修改一条记录语句update public class JDBCDemo02 { 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 student set namee='李四' where id = 4"; //3.获取Connection对象 conn = DriverManager.getConnection("jdbc:mysql:///db1","root","123456"); //4.获取执行sql的对象Statement stmt = conn.createStatement(); //5.执行sql int count = stmt.executeUpdate(sql); //count是影响的行数 //6.处理结果 System.out.println(count); if(count>0){ System.out.println("修改成功!"); }else{ System.out.println("修改失败 !"); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ if(stmt != null){ try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } }
package ln.javatest.day01.demo01; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; //student表,删除一条记录语句delete public class JDBCDemo02 { 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 student where id = 4"; //3.获取Connection对象 conn = DriverManager.getConnection("jdbc:mysql:///db1","root","123456"); //4.获取执行sql的对象Statement stmt = conn.createStatement(); //5.执行sql int count = stmt.executeUpdate(sql); //count是影响的行数 //6.处理结果 System.out.println(count); if(count>0){ System.out.println("删除成功!"); }else{ System.out.println("删除失败 !"); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ if(stmt != null){ try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } }
package ln.javatest.day01.demo01; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; //DDL创建一个表(DDL没有返回值,只有一个0) public class JDBCDemo02 { public static void main(String[] args) { Connection conn = null; Statement stmt = null; try { //1.驱动注册 Class.forName("com.mysql.jdbc.Driver"); //2.定义sql String sql = "create table stu(id int,name varchar(20))"; //3.获取Connection对象 conn = DriverManager.getConnection("jdbc:mysql:///db1","root","123456"); //4.获取执行sql的对象Statement stmt = conn.createStatement(); //5.执行sql int count = stmt.executeUpdate(sql); //DDL没有返回值,只有0 //6.处理结果 System.out.println(count); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ if(stmt != null){ try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } }
4.ResultSet:结果集对象,封装查询结果
1)boolean next():游标向下移动一行,(游标一开始默认在最上面字段行),判断当前行是否是末尾行(是否有数据),如果是,则返回false,如果不是则返回true。
2)getXxx(参数):获取数据
1)Xxx:代表数据类型,如 :int getInt(),String getString();
2)参数:
1.1int:代表列的编号,从1开始 如:getString(1)
1.2String:代表列名称 如:getDoubel('sorce")
3)使用步骤:
1.游标向下移动一行
2.判断是否有数据
3.获取数据
package ln.javatest.day01.demo01; import java.sql.*; public class JDBCDemo03 { public static void main(String[] args) { Connection conn = null; Statement stat = null; ResultSet rs = null; try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //定义sql对象 String sql = "select * from student"; //获取连接对象 conn = DriverManager.getConnection("jdbc:mysql:///db1", "root", "123456"); //获取执行sql对象 stat = conn.createStatement(); //执行sql(DQL用executeQuery()来执行) rs = stat.executeQuery(sql); //处理结果 //循环判断游标是否是最后一行的末尾 while(rs.next()){ //获取数据 int id = rs.getInt(1); String namee = rs.getString("namee"); int sorce = rs.getInt(1); String sex = rs.getString("sex"); int age = rs.getInt(1); System.out.println(id+"--"+namee+"--"+sorce+"--"+sex+"--"+"age"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); }finally{ if(stat!= null){ try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!= null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(rs!= null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } }
练习:
package ln.javatest.day01.demo01; /* 练习: 定义一个方法,查询Student表的数据并将其封装为一个对象,然后装载集合,返回。 1.定义一个Student类 2.定义方法public List<Student> findAll(){} 3.实现方法select * from student; */ import java.sql.*; import java.util.ArrayList; import java.util.List; public class JDBCDemo04 { public static void main(String[] args) { //成员变量,需要new对象才能使用 //静态方法,类名直接点就可以用 JDBCDemo04 jd4 = new JDBCDemo04(); List<Student> list1 =jd4.findAll(); System.out.println(list1); } //查询所有Student对象 public List<Student> findAll(){ //成员变量,需要new对象才能使用 Connection conn = null; Statement stat = null; ResultSet rs = null; List<Student> list = null; try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //定义sql String sql = "Select * from Student"; //获取连接 conn = DriverManager.getConnection("jdbc:mysql:///db1", "root", "123456"); //获取执行sql的对象 stat = conn.createStatement(); //执行sql rs = stat.executeQuery(sql); //遍历结果集,封装对象,装载集合 Student s = null; list = new ArrayList<>(); while(rs.next()){ //获取数据 int id = rs.getInt(1); String namee = rs.getString("namee"); int sorce = rs.getInt(1); String sex = rs.getString("sex"); int age = rs.getInt(1); //创建Student对象,并赋值 s = new Student(); s.setId(id); s.setNamee(namee); s.setSorce(sorce); s.setSex(sex); s.setAge(age); //装载集合 list.add(s); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); }finally { if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } return list; } }
注意:可以抽取JDBC工具类:JDBCUtils
1) 目的:简化书写
2)分析:
1.抽取一个注册驱动
需求:不想传递参数(麻烦),还得保证工具类的通用性
解决:配置文件
jdbc.properties
ur1=
user=
password=
2.抽取一个方法获取连接多想
3.抽取一个方法释放资源
ur1=jdbc:mysql:///db1 user=root password=123456 driver=com.mysql.jdbc.Driver
package ln.javatest.day01.demo01; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.sql.*; import java.util.Properties; //JDBC工具类 public class JDBCUtils { 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); //2.加载文件 pro.load(new FileReader(path)); //3.获取数据源,赋值 url=pro.getProperty("ur1"); 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(); } } //获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,user,password); } //释放资源 public static void close(Statement stat, Connection conn){ if(stat!=null){ try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } public static void close(ResultSet rs, Statement stat, Connection conn){ if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } }
package ln.javatest.day01.demo01; /* 演示jdbc工具类 */ import java.sql.*; import java.util.ArrayList; import java.util.List; public class JDBCDemo05 { public static void main(String[] args) { //成员变量,需要new对象才能使用 //静态方法,类名直接点就可以用 JDBCDemo05 jd4 = new JDBCDemo05(); List<Student> list1 =jd4.findAll(); System.out.println(list1); } //查询所有Student对象 public List<Student> findAll(){ //成员变量,需要new对象才能使用 Connection conn = null; Statement stat = null; ResultSet rs = null; List<Student> list = null; try { /*//注册驱动 Class.forName("com.mysql.jdbc.Driver"); //获取连接 conn = DriverManager.getConnection("jdbc:mysql:///db1", "root", "123456");*/ conn = JDBCUtils.getConnection(); //定义sql String sql = "Select * from Student"; //获取执行sql的对象 stat = conn.createStatement(); //执行sql rs = stat.executeQuery(sql); //遍历结果集,封装对象,装载集合 Student s = null; list = new ArrayList<>(); while(rs.next()){ //获取数据 int id = rs.getInt(1); String namee = rs.getString("namee"); int sorce = rs.getInt(1); String sex = rs.getString("sex"); int age = rs.getInt(1); //创建Student对象,并赋值 s = new Student(); s.setId(id); s.setNamee(namee); s.setSorce(sorce); s.setSex(sex); s.setAge(age); //装载集合 list.add(s); } } catch (SQLException throwables) { throwables.printStackTrace(); }finally { /*if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } }*/ JDBCUtils.close(rs,stat,conn); } return list; } }
练习:
1.通过键盘录入用户名和密码
2.判断用户是否登录成功
ur1=jdbc:mysql:///db1 user=root password=123456 driver=com.mysql.jdbc.Driver
package ln.javatest.day01.demo01; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.sql.*; import java.util.Properties; //JDBC工具类 public class JDBCUtils { 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); //2.加载文件 pro.load(new FileReader(path)); //3.获取数据源,赋值 url=pro.getProperty("ur1"); 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(); } } //获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,user,password); } //释放资源 public static void close(Statement stat, Connection conn){ if(stat!=null){ try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } public static void close(ResultSet rs, Statement stat, Connection conn){ if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } }
package ln.javatest.day01.demo01; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; /* 登录的练习: 1.通过键盘录入用户名和密码 2.判断用户是否登录成功 */ public class JDBCDemo06 { public static void main(String[] args) { //1.键盘录入,接受用户名和密码 Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.next(); System.out.println("请输入密码"); String password = sc.next(); //2.调用方法 boolean flag = new JDBCDemo06().login(username, password); //3.判断结果,输出不同语句 if(flag){ //登录成功 System.out.println("登陆成功"); }else{ System.out.println("用户或密码错误"); } } //登录方法 public boolean login(String username,String password){ Connection conn = null; Statement stat = null; ResultSet rs = null; if(username==null || password==null){ return false; } //连接数据库判断是否登录成功 //1.获取连接 try { conn = JDBCUtils.getConnection(); //2.定义sql String sql = "select * from user where username = '"+username+"' and password = '"+password+"'"; //3.获取执行sql的对象 stat = conn.createStatement(); //4.执行查询 rs = stat.executeQuery(sql); //5.判断 return rs.next(); //有下一行返回ture } catch (SQLException throwables) { throwables.printStackTrace(); }finally { JDBCUtils.close(rs,stat,conn); } return false; } }
5.PreparedStatement:执行sql的对象
1)SQL注入问题:
在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
1.输入用户名随便,输入密码:a' or 'a' = 'a
2.sql:select * from user where username = 'dhiwndfb' and password = a' or 'a' = 'a
2)解决sql注入问题:使用PreparedStatement对象来解决
3)预编译的SQL:参数使用?作为占位符
4)步骤:
1.导入驱动jar包
1.复制jar包到项目的自己创建的文件夹下
2.右击文件夹--> add as 自己创建的文件夹
2.注册驱动
3.获取数据库连接对象Connection
4.定义sql
注意:sql的参数使用?作为占位符
5.获取执行sql语句的对象PreparedStatement
6.给?赋值
方法:setXxx(参数1,参数2)
参数1:?的位置编号,从1开始
参数2:?的值
7.执行sql,接收返回结果
8.处理结果
9.要释放获取的资源package ln.javatest.day01.demo01; import java.sql.*; import java.util.Scanner; /* 使用PreparedStatement接口实现 登录的练习: 1.通过键盘录入用户名和密码 2.判断用户是否登录成功 */ public class JDBCDemo07 { public static void main(String[] args) { //1.键盘录入,接受用户名和密码 Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.next(); System.out.println("请输入密码"); String password = sc.next(); //2.调用方法 boolean flag = new JDBCDemo07().login(username, password); //3.判断结果,输出不同语句 if(flag){ //登录成功 System.out.println("登陆成功"); }else{ System.out.println("用户或密码错误"); } } //登录方法 public boolean login(String username,String password){ Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; if(username==null || password==null){ return false; } //连接数据库判断是否登录成功 //1.获取连接 try { conn = JDBCUtils.getConnection(); //2.定义sql String sql = "select * from user where username = ? and password = ?"; //3.获取执行sql的对象 pstat = conn.prepareStatement(sql); //给?赋值 pstat.setString(1,username); pstat.setString(2,password); //4.执行查询 rs = pstat.executeQuery(); //5.判断 return rs.next(); //有下一行返回ture } catch (SQLException throwables) { throwables.printStackTrace(); }finally { JDBCUtils.close(rs,pstat,conn); } return false; } }
JDBC控制事务:
1.事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则着多个步骤要么同时成功,要么同时失败。
2.操作:
1)开启事务
2)提交事务
3)回滚事务
3.使用Connection对象来管理事务
1)开启事务:setAutoCommit(boolean autoCommit)
调用该方法设置参数为false,即开启事务
再执行sql之前开启事务
2)提交事务:commit ()
当所有sql都执行完提交事务
3)回滚事务:rollback ()
在catch中回滚事务package ln.javatest.day01.demo01; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; //事务操作 public class JDBCDemo08 { public static void main(String[] args) { Connection conn = null; PreparedStatement pstat1 = null; PreparedStatement pstat2 = null; try { //1.获取连接 //开启事务 conn.setAutoCommit(false); conn = JDBCUtils.getConnection(); //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对象 pstat1 = conn.prepareStatement(sql1); pstat2 = conn.prepareStatement(sql2); //4.设置参数 pstat1.setDouble(1,500); pstat1.setInt(2,1); pstat2.setDouble(1,500); pstat2.setInt(2,2); //5.执行sql pstat1.executeUpdate(); //手动制造异常 int i= 3/0; pstat2.executeUpdate(); //提交事务 conn.commit(); } catch (SQLException throwables) { //事务回滚 try { if(conn != null){ conn.rollback(); } } catch (SQLException e) { e.printStackTrace(); } throwables.printStackTrace(); }finally { JDBCUtils.close(pstat1,conn); JDBCUtils.close(pstat2,null); } } }