【Java EE】Day05 JDBC概念、对象、控制事务
一、基本概念
1、概念
- Java Database Connectivity:Java数据库连接
2、本质
- SUN公司提供的操作所有关系型数据库的规则,是一套接口
- 各厂商实现此接口,提供相应的驱动jar包供我们使用‘’
- jar包内是编译好的字节码文件
- src目录对应开源的源码文件
- 真正执行的是jar包中的实现类
3、快速入门
- 导入jar包到libs目录下,右键add as libarary
- 执行过程
- 注册驱动
- 驱动管理类DriverManager获取连接对象
- 定义sql并获取sql执行对象Statement/预编译sql对象PreparedStatement
- 执行sql接收返回结果(通过结果集对象ResultSet)并进行处理
- 释放资源,避免内存泄露
package cn.itcast.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; /** * JDBC快速入门 */ public class JdbcDemo1 { public static void main(String[] args) throws Exception{ //1.导入驱动jar包mysql-connector-java-5.1.37-bin.jar //创建libs文件夹便于管理 //复制后右键,add as library //2.注册驱动 Class.forName("com.mysql.jdbc.Driver"); //3.获取数据库的连接对象 Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3","root","root"); //4.定义一个SQL语句 String sql="update account set balance = 500 where id=1";//sql语句后不用加分号 //5.获取SQL的执行对象 Statement stmt = conn.createStatement(); //6.执行SQL int count = stmt.executeUpdate(sql); //7.处理结果,打印 System.out.println(count); //8.释放资源 stmt.close(); conn.close(); } }
二、各个对象详解
1、DriverManager--注册驱动、获取连接
- 注册驱动:Class.forName("com.mysql.jdbc.Driver");
- 作用同DriverManager.registerDriver(Driver driver)---Dirver类的静态代码块中包含
- MySQL5后可以省略
- 获取连接:
- Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3","root","root");
- URL本地3306端口可以简写为:jdbc:mysql///数据名
2、Connection--获取执行对象、事务管理
- 获取执行对象:
- Statement stmt = conn.createStatement();
- PreparedStatement pstmt = conn.prepareStatement(String sql);
- 管理事务:
- 概念:多步操作,要么同时成功要么同时失败
- 开启事务:conn.setAutoCommit(false)
- 提交事务:conn.commit()
- 回滚事务:conn.rollback();
3、Statement--SQL执行
- boolean execute(sql):任意语句
- int executeUpdate(sql) :DDL/DML,DDL只会返回0
- ResultSet executeQuery(String sql):DQL
4、ResultSet--结果集对象,封装查询结果
- 通过游标rs.next()向下移动一行取结果rs.getInt(1)/getDouble("学号");
5、JDBCUtils--抽取工具类
- 之前:每次都要注册驱动、获取连接
- 现在:编写方法,并通过配置文件获取连接
package cn.itcast.utils; 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{ //读取配置资源文件,获取值 //BufeeredReader。。。麻烦 try { //1.创建Properties集合类 Properties prop=new Properties(); //2.加载文件,代码提示 //prop.load(new FileReader("src/jdbc.properties")); //找不到资源文件,最笨的方法---可以写绝对路径D:\IdeaProjects\liujinhui\day04_jdbc_20201220\src\jdbc.properties //另外:获取src路径下的文件--->ClassLoader 类加载器:可以 加载字节码文件进内存,同时可以获取src下的资源文件 ClassLoader classLoader = JDBCUtils.class.getClassLoader(); //传的是以src相对的文件路径 //返回统一资源定位符,即文件的绝对路径 URL res= classLoader.getResource("jdbc.properties"); String path = res.getPath(); System.out.println(path); prop.load(new FileReader(path)); //3.获取数据,赋值 url=prop.getProperty("url"); user=prop.getProperty("user"); password=prop.getProperty("password"); driver=prop.getProperty("driver"); //4.注册驱动 Class.forName(driver); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //Arrays等都是静态,方便类直接调用 /** * 获取连接的工具方法 * @return 连接对象 */ //String url,String root,String password有参数仍然很麻烦 //通过私有变量、配置文件及静态代码块解决 public static Connection getConnection() throws SQLException{ return DriverManager.getConnection(url,user,password); } /** * 释放资源 * @param stmt * @param conn */ public static void close(Statement stmt,Connection conn){ if (stmt!=null){ try { stmt.close(); //conn.close();多个语句要放到多个try..catch中 } catch (SQLException e) { e.printStackTrace(); } } if (conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * 释放资源 * @param rs * @param stmt * @param conn */ public static void close(ResultSet rs, Statement stmt, Connection conn){ if (stmt!=null){ try { stmt.close(); //conn.close();多个语句要放到多个try..catch中 } catch (SQLException e) { e.printStackTrace(); } } if (conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } if (rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
- 测试
public class JDBCDemo8 { public static void main(String[] args) { //想调用非静态方法,则需要创建对象 List<Emp> list = new JDBCDemo8().findAll2(); System.out.println(list); } /** * 演示JDBC工具类 * @return */ public List<Emp> findAll2(){ Connection conn=null; Statement stmt=null; ResultSet rs=null; List<Emp> list=null; try { //1.注册驱动 //Class.forName("com.mysql.jdbc.Driver");//最好写,写上可以向下兼容 //2.获取连接 //conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); conn=JDBCUtils.getConnection(); //3.定义sql String sql="select * from emp"; //4.获取执行sql的对象 stmt = conn.createStatement(); //5.执行sql rs = stmt.executeQuery(sql); //6.遍历结果集,封装对象,装载集合 Emp emp=null; list = new ArrayList<>(); while(rs.next()){ //获取数据 int id = rs.getInt("id"); String ename = rs.getString("ename"); int job_id = rs.getInt("job_id"); int mgr = rs.getInt("mgr"); //怎么把光标放上就能显示概述? //Date是sql包下的类,继承了util的date,子类继承父类 Date joindate = rs.getDate("joindate"); double salary = rs.getDouble("salary"); double bonus = rs.getDouble("bonus"); int dept_id = rs.getInt("dept_id"); //封装对象,对象引用复用 emp=new Emp(); emp.setId(id); emp.setBonus(bonus); emp.setDept_id(dept_id); emp.setEname(ename); emp.setJoindate(joindate); emp.setMgr(mgr); emp.setSalary(salary); list.add(emp); } }catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtils.close(rs,stmt,conn); } return list; } }
6、PreparedStatement:预编译SQL执行对象
- 之前问题:SQL注入问题
- 预编译的SQL,使用?作为占位符
- 好处:解决SQL注入,效率更高
package cn.itcast.jdbc; import cn.itcast.utils.JDBCUtils; import java.sql.*; import java.util.Scanner; /** * 使用PrepareStatement实现登录操作 * 练习: 通过键盘录入用户名和密码 判断用户名是否登录成功 */ public class JDBCDemo10 { public static void main(String[] args) { //1.键盘录入,接收用户名和密码 Scanner sc=new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.nextLine(); System.out.println("请输入密码:"); String password = sc.nextLine(); //2.调用方法 //静态调用非静态需要声明对象 boolean flag = new JDBCDemo10().login(username, password); //3.判断结果,输出不同语句 if (flag){ //登录成功 System.out.println("登录成功"); }else{ System.out.println("用户名或密码错误"); } //2.调用方法 //3.判断结果,输出不同语句 } /** * 登录方法 */ 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 user where username= ? and password= ?"; //System.out.println(sql); //3.获取执行SQL的对象 pstmt = conn.prepareStatement(sql); //给 ?赋值 pstmt.setString(1,username); pstmt.setString(2,password); //4.执行查询 rs =pstmt.executeQuery(); //5.判断 /*if (rs.next()){ return true; }else{ return false; }*/ //直接返回 return rs.next(); } catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtils.close(rs,pstmt,conn); } return false; } }
三、使用JDBC控制事务
1、注意
- 在执行sql之前开启事务setAutoCommit()
- 在当所有sql执行完提交事务
- 在 catch中回滚事务
2、使用(转账操作等)
package cn.itcast.jdbc; import cn.itcast.utils.JDBCUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * 事务操作 */ public class JDBCDemo11 { 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-500 where id=1"; //2.2 李四+500 //String sql2="update account set balance=balance+500 where id=2"; //通用写法 String sql1="update account set balance=balance-? where id=?"; 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 pstmt1.executeUpdate(); //手动制造异常 int i=3/0; pstmt2.executeUpdate(); //提交事务 conn.commit(); //使用大异常 } catch (Exception e) { try { //事务回滚,前提不为null if (conn!=null){ conn.rollback(); } } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { JDBCUtils.close(pstmt1,conn); JDBCUtils.close(pstmt2,null); } } }
本文来自博客园,作者:哥们要飞,转载请注明原文链接:https://www.cnblogs.com/liujinhui/p/14851547.html