一、JDBC的六步骤(背过)
第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)
第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行SQL语句(DQL DML….)
第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)
import java.sql.*;public class JDBCTest01 {public static void main(String[] args) {Connection conn =null;Statement stmt = null;ResultSet rs =null;try{//1.注册驱动Class.forName("com.mysql.jdbc.Driver");//2.获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");//3.获取数据库操作对象stmt = conn.createStatement();//4.执行sql//int executeUpdate(insert/delete/update)//ResultSet executeQuery(select)String sql ="select empno as a,ename,sal from emp";rs =stmt.executeQuery(sql);//5.处理查询结果集while(rs.next()){/*// 以指定的格式取出int empno = rs.getInt(1);String ename = rs.getString(2);double sal = rs.getDouble(3);System.out.println(empno + "," + ename + "," + (sal + 100));*/// 按下标取出,程序不健壮int empno = rs.getInt("a");String ename = rs.getString("ename");double sal = rs.getDouble("sal");System.out.println(empno + "," + ename + "," + (sal + 200));}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();// 6、释放资源}finally{if(rs != null){try{rs.close();} catch (Exception e){e.printStackTrace();}}if(stmt != null){try{stmt.close();} catch (Exception e){e.printStackTrace();}}if(conn != null){try{conn.close();} catch (Exception e){e.printStackTrace();}}}}}
二、SQL问题
该问题存在BUG
用户名:fdsa
密码:fdsa’ or ‘1’=’1登录成功
这种现象被称为SQL注入(安全隐患)。(黑客经常使用)5、导致SQL注入的根本原因是什么?
用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到SQL注入。
package ustc.java.jdbc;import java.sql.*;import java.util.HashMap;import java.util.Map;import java.util.Scanner;/*模拟实现用户登录功能*/public class JDBCTest06 {public static void main(String[] args) {// 初始化界面Map<String,String> userLoginInfo = initUI();// 验证用户名和密码boolean loginSuccess = login(userLoginInfo);// 输出最后结果System.out.println(loginSuccess ? "登录成功" : "登录失败");}/*** 用户登录* @param userLoginInfo 用户登录信息* @return true表示登录成功,false表示登录失败*/private static boolean login(Map<String, String> userLoginInfo) {//单独定义变量String loginName = userLoginInfo.get("loginName");String loginPwd = userLoginInfo.get("loginPwd");boolean loginSuccess = false;Connection conn = null;Statement stmt = null;ResultSet rs = null;try {// 1、注册驱动Class.forName("com.mysql.jdbc.Driver");// 2、获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");// 3、获取数据库操作对象stmt = conn.createStatement();// 4、执行sql语句String sql = "select * from t_user where loginName = '"+ loginName+ "' and loginPwd = '" + loginPwd+ "'";rs = stmt.executeQuery(sql);// 5、处理结果集if(rs.next()) {loginSuccess = true;}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.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 loginSuccess;}/*** 初试化界面* @return 用户输入的用户名和密码等登录信息*/private static Map<String, String> initUI() {Scanner s = new Scanner(System.in);System.out.print("请输入用户:");String loginName = s.nextLine();System.out.print("请输入密码:");String loginPwd= s.nextLine();Map<String,String> userLoginInfo = new HashMap<>();userLoginInfo.put("loginName",loginName);userLoginInfo.put("loginPwd",loginPwd);return userLoginInfo;}}
解决SQL注入问题
3、解决SQL注入的关键是什么?
用户提供的信息中即使含有sql语句的关键字,但是这些关键字并没有参与编译。不起作用。4、对比一下statement和Preparedstatement?
Statement存在sql注入问题,Preparedstatement解决了SQL注入问题。
Statement是编译一次执行一次。PreparedStatement是编译一次,可执行多次。Preparedstatement效率较高一些。Preparedstatement会在编译阶段做类型的安全检查。
package ustc.java.jdbc;import java.sql.*;import java.util.HashMap;import java.util.Map;import java.util.Scanner;public class JDBCTest07 {public static void main(String[] args) {// 初始化界面Map<String,String> userLoginInfo = initUI();// 验证用户名和密码boolean loginSuccess = login(userLoginInfo);// 输出最后结果System.out.println(loginSuccess ? "登录成功" : "登录失败");}/*** 用户登录* @param userLoginInfo 用户登录信息* @return true表示登录成功,false表示登录失败*/private static boolean login(Map<String, String> userLoginInfo) {boolean loginSuccess = false;Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {// 1、注册驱动Class.forName("com.mysql.jdbc.Driver");// 2、获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");// 3、获取预编译的数据库操作对象// sql语句的框架中,一个?,表示一个占位符,一个?将来接收一个值。注意:?不要用单引号括起来String sql = "select * from t_user where loginName = ? and loginPwd = ?";// 程序执行到此处,会发送sql语句框架给DBMS,DBMS对sql语句框架进行预编译。ps = conn.prepareStatement(sql);// 给占位符?传值,第一个?的下标是1,第二个?的下标是2(JDBC中下标都从1开始)ps.setString(1,userLoginInfo.get("loginName"));ps.setString(2,userLoginInfo.get("loginPwd"));// 4、执行sql语句rs = ps.executeQuery();// 5、处理结果集if(rs.next()) {loginSuccess = true;}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();} finally {// 6、释放资源if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return loginSuccess;}/*** 初试化界面* @return 用户输入的用户名和密码等登录信息*/private static Map<String, String> initUI() {Scanner s = new Scanner(System.in);System.out.print("请输入用户:");String loginName = s.nextLine();System.out.print("请输入密码:");String loginPwd = s.nextLine();Map<String,String> userLoginInfo = new HashMap<>();userLoginInfo.put("loginName",loginName);userLoginInfo.put("loginPwd",loginPwd);return userLoginInfo;}}
演示statement的用途
即什么时候使用statement
综上所述: Preparedstatement使用较多。只有极少数的情况下需要使用statement5、什么情况下必须使用statement呢?
业务方面要求必须支持sql注入的时候。
statement支持sql注入,凡是业务方面要求是需要进行sql语句拼接的,必须使用statement。
package ustc.java.jdbc;import java.sql.*;import java.util.Scanner;public class JDBCTest08 {public static void main(String[] args) {//用户在控制台输入desc就是降序,输入asc就是升序Scanner s = new Scanner(System.in);System.out.println("请输入desc或者asc");String keyWords = s.nextLine();//执行SQLConnection conn = null;Statement stmt = null;ResultSet rs = null;try {Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");stmt = conn.createStatement();String sql = "select ename from emp order by ename " + keyWords;rs = stmt.executeQuery(sql);//遍历结果集while(rs.next()){System.out.println(rs.getString("ename"));}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();} finally {if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (stmt != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}}
三、JDBC事务机制
JDBC事务机制:
1、JDBc中的事务是自动提交的,什么是自动提交?
只要执行任意一条DML语句,则自动提交—次。这是JDBC默认的事务行为。但是在实际的业务当中,通常都是N条DML语句共同联合才能完成的,必须保证他们这些DML语句在同一个事务中同时成功或者同时失败。
文件名:t_act.sql 用途:bjpowernode; source …
drop table if exists t_act;create table t_act(actno int,balance double(7,2)//注意7表示有效数字的个数,2表示小数位的个数。);insert into t_act(actno,balance) values(111,20000);insert into t_act(actno,balance) values(222,0);commit;select * from t_act;
/*重点三行代码:conn.setAutoCommit(false);conn.commit();conn.rollback();*/package ustc.java.jdbc;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException;public class JDBCTest10 {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;try {// 注册驱动Class.forName("com.mysql.jdbc.Driver");// 获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");// 将自动提交改为手动提交conn.setAutoCommit(false);// 获取预编译的数据库操作对象String sql = "update t_act set balance = ? where actno = ? ";ps = conn.prepareStatement(sql);ps.setInt(1,10000);ps.setDouble(2,111);// 执行sql语句int count = ps.executeUpdate();/*String s = null;s.toString();*/ps.setInt(1,10000);ps.setDouble(2,222);count += ps.executeUpdate();System.out.println(count == 2 ? "转账成功" : "转账失败");// 程序能执行到此处,说明没有异常,事务结束,手动提交数据conn.commit();} catch (Exception e) {// 遇到异常,回滚if (conn != null) {try {conn.rollback();} catch (SQLException throwables) {throwables.printStackTrace();}}e.printStackTrace();} finally {// 释放资源if (ps != null) {try {ps.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}}
四、JDBC工具类的封装
package ustc.java.jdbc;import java.sql.*;/*JDBC工具类,简化JDBC编程*/public class DBUtil {/*** 工具类中的构造方法是私有的* 因为工具类中的方法都是静态的,不需要new对象,直接通过类名去调即可。*/private DBUtil(){}/*** 静态代码块,类加载的时候执行* 把注册驱动程序的代码放在静态代码块中,避免多次获取连接对象时重复调用*/static {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}public static Connection getConnection() throws SQLException {return DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");}/*** 关闭资源* @param conn 连接对象* @param ps 数据库操作对象* @param rs 结果集*/public static void close(Connection conn, Statement ps, ResultSet rs){if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}
测试DBUtil工具类和模糊查询
package ustc.java.jdbc;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;/*1、测试DBUtil工具类2、模糊查询*/public class JDBCTest {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = DBUtil.getConnection();String sql = "select ename from emp where ename like ?";ps = conn.prepareStatement(sql);ps.setString(1,"_A%");rs = ps.executeQuery();while(rs.next()){System.out.println(rs.getString("ename"));}} catch (SQLException throwables) {e.printStackTrace();}finally{DBUtil.close(conn,ps,rs);}}
