JDBC JavaEE 数据库

2020-06-09 约 2930 字 阅读时长6 分钟

JDBC

简介

  1. JDBC: Java Database Connectivity(Java语言连接数据库)
  2. JDBC是sun公司定制的一套接口(Java.sql.*) 接口都有调用者和实现者 面向接口调用、面向接口写实现类都是面向接口编程 面向接口:解耦合,降低偶尔度,提高程序扩展力;多态是典型的面向接口编程
  3. 数据库厂家实现接口(驱动),Java程序员调用接口
  4. 首先官网下载对应的Java驱动包,然后将其配置到环境变量classpath中,使用IDEA不需要配置以上环境变量
  5. JDBC变成六步
    1. 注册驱动:告诉Java程序,即将链接哪个品牌数据库
    2. 获取链接:表示JVM进程与数据库进程之间的通道打开了,这属于进程间通信,重量级的,使用完后需要释放
    3. 获取数据库操作对象:专门执行sql语句的对象
    4. 执行sql语句:DQL,DML
    5. 执行查询结果集:只有当第四步执行的是select语句时,才有这一步
    6. 释放资源:释放资源,Java与mysql之间属于进程间通信

编程六步

  1. 结果集有next()方法(有点像是迭代器),有数据返回true,没有数据返回false; getString()方法,不管数据库字段类型是什么,取出都是String类型; 还可以使用int取出,getInt(); 可以使用下标取出,也可以使用字段名取出(查询的字段名) JDBC中下标从1开始
java
 1import Java.sql.*;
 2import Java.util.*;
 3public class  JdbcTest01
 4{
 5	public static void main (String[] args) throws Exception
 6	{
 7		//使用资源绑定器
 8		ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
 9
10		Connection conn=null;
11		Statement stmt=null;
12		ResultSet rs=null;
13		try{
14			//1.注册驱动
15			//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
16			//注册驱动另一种方式,在静态代码块中,使用反射机制加载类,参数是字符串,
17			//可以写到properties文件中
18			Class.forName(bundle.getString("driver"));
19
20			//2.获取连接
21			/*
22				url包括协议、IP、port、资源名
23			*/
24			String url=bundle.getString("url");
25			String user=bundle.getString("user");
26			String password=bundle.getString("password");
27			conn=DriverManager.getConnection(url,user,password);
28			System.out.println(conn);
29
30			//3.获取数据库操作对象(专门执行sql语句的)
31			stmt=conn.createStatement();
32
33			//4.执行sql语句
34			String sql="insert into t_user(name) values ('北京')";
35			//专门执行DML语句(insert delete update);返回值int为影响记录条数
36			int count=stmt.executeUpdate(sql);	
37			System.out.println(count==1?"插入成功":"插入失败");
38			sql="select * from emp;";
39			//专门执行DQL语句,ResultSet executeQuery(select)
40			rs=stmt.executeQuery(sql);
41
42			//5.查询结果集
43			while(rs.next()){//看是否还有数据
44				System.out.print(rs.getString("ename")+"."); //查询出结果的字段名
45				System.out.print(rs.getString("sal")+".");
46				System.out.print(rs.getString("deptno")+".");
47				System.out.print(rs.getString("job")+".");
48				System.out.println();
49				
50			}
51		}catch(Exception e){
52			e.printStackTrace();
53		}finally{
54			//6.释放资源,遵循从小到大依次关闭
55			try{
56				if(rs!=null){
57					rs.close();
58				}
59			}catch(SQLException e){
60				e.printStackTrace();
61			}
62			try{
63				if(stmt!=null){
64					stmt.close();
65				}
66			}catch(SQLException e){
67				e.printStackTrace();
68			}
69			try{
70				if(conn!=null){
71					conn.close();
72				}
73			}catch(SQLException e){
74				e.printStackTrace();
75			}
76		}
77		
78	}
79}

资源绑定器

jdbc.properties

properties
1driver=com.mysql.jdbc.Driver
2url=jdbc:mysql://localhost:3306/mydata?useSSL=false
3user=root
4password=123456
java
1//使用资源绑定器
2ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
3String url=bundle.getString("url");
4String user=bundle.getString("user");
5String password=bundle.getString("password");

sql注入

  1. 原因:用户输入的信息中含有sql语句关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲

  2. 解决

    1. 用户输入信息不参与sql语句编译过程,预编译,占位符?
    2. sql语句如果完全不变,那么第二次执行时不会重新编译;所以有PreparedStatement预编译,且它执行效率高于Statement;PreparedStatement会在编译阶段做类型的安全检查
    3. Statement(数据库操作接口)更换为PreparedStatement(预编译数据库操作接口,继承Statement);PreparedStatement预先对sql语句进行编译
    4. ps=conn.prepareStatement(sql);获取预编译操作对象;这里会发送sql语句框架发送到DBMS,然后DBMS进行预编译;?占位符
    5. 给?占位符传值,第一个是问号下标是1,第二个问号下标是2,JDBC中所有下标从1开始;ps.setString(1,username);ps.setString(2,password);这里会根据传值类型自动书写sql语句
    6. res=ps.executeQuery();//执行sql
    java
     1Connection conn=null;
     2PreparedStatement ps=null;//预编译数据库操作对象
     3ResultSet res=null;
     4try {
     5     Class.forName("com.mysql.jdbc.Driver");
     6    	conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata?useSSL=false","root","123456");
     7//获取预编译操作对象;此时会先编译;?占位符
     8	String sql="select * from t_user where loginName=? and loginPwd=?;";
     9	ps=conn.prepareStatement(sql);
    10//给占位符传值
    11	ps.setString(1,userInfo.get("username"));
    12	ps.setString(2,userInfo.get("password"));
    13//执行sql语句,因为语句不变,不会重新编译
    14	res=ps.executeQuery();
    15	if (res.next()){
    16		loginSuccess=true;
    17	}
    18}catch(Exception e){}finally{}
  3. 当业务方面要求必须使用sql注入时,必须使用Statement;比如升序降序,如果用PreparedStatement会将desc或esc加上引号,不符合逻辑

  4. PreparedStatement增删改代码

    java
sql
 1package com.leiking.userlogin;
 2
 3import Javax.swing.plaf.nimbus.State;
 4import Java.sql.*;
 5import Java.util.HashMap;
 6import Java.util.Map;
 7import Java.util.Scanner;
 8
 9public class LoginMain {
10    public static void main(String[] args) {
11        //初始化界面
12        Map<String,String> userInfo=initUI();
13        //验证用户名和密码
14        boolean bol=login(userInfo);
15        //输出结果
16        System.out.println(bol==true?"登陆成功":"登陆失败");
17    }
18
19    private static boolean login(Map<String, String> userInfo) {
20        boolean loginSuccess=false;
21        Connection conn=null;
22        Statement stat=null;
23        ResultSet res=null;
24        try {
25            Class.forName("com.mysql.jdbc.Driver");
26            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata?useSSL=false");
27            stat=conn.createStatement();
28            String sql="select * from t_user where " +
29                    "loginName='"+userInfo.get("username")+
30                    "' and loginPwd='"+userInfo.get("password")+"';";
31            res=stat.executeQuery(sql);
32            if (res.next()){
33                loginSuccess=true;
34            }
35            return loginSuccess;
36        } catch (ClassNotFoundException e) {
37            e.printStackTrace();
38        } catch (SQLException throwables) {
39            throwables.printStackTrace();
40        }finally {
41            if (res!=null){
42                try {
43                    res.close();
44                } catch (SQLException throwables) {
45                    throwables.printStackTrace();
46                }
47            }
48            if (stat!=null){
49                try {
50                    stat.close();
51                } catch (SQLException throwables) {
52                    throwables.printStackTrace();
53                }
54            }
55            if (conn!=null){
56                try {
57                    conn.close();
58                } catch (SQLException throwables) {
59                    throwables.printStackTrace();
60                }
61            }
62        }
63        return true;
64    }
65
66    /**
67     * 初始化用户界面
68     * @return 用户输入的用户名与信息
69     */
70    private static Map<String, String> initUI() {
71        Scanner s=new Scanner(System.in);
72        System.out.print("输入用户名:");
73        String username=s.nextLine();
74        System.out.println();
75        System.out.print("输入密码:");
76        String password=s.nextLine();
77        System.out.println();
78        Map<String,String> userInfo=new HashMap<>();
79        userInfo.put("username",username);
80        userInfo.put("password",password);
81        return userInfo;
82    }
83}
84//sql注入现象
85//输入:用户名:fdss;密码:125' or '1'='1
86select * from t_user where loginName='fdss' and loginPwd='125' or 1 = '1

单机事务

  1. JDBC中事务是自动提交的,执行任意一条DML语句,则会提交依次,这是JDBC默认事务行为
  2. conn.setAutoCommit(false):关闭事务自动提交
  3. conn.commit():手动提交事务
  4. conn.rollback():手动回滚事务;当sql语句出错时执行回滚,保证数据安全
java
 1Connection conn=null;
 2        PreparedStatement ps=null;
 3        try {
 4            //1.注册驱动
 5            Class.forName("com.mysql.jdbc.Driver");
 6            //2.连接数据库
 7            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata","root","123456");
 8            //3.获取数据库预编译操作对象
 9            conn.setAutoCommit(false);//关闭事务自动提交
10            String sql="update t_act set money=? where nameno=?";
11            ps=conn.prepareStatement(sql);
12            //2001账户减钱
13            ps.setDouble(1,10000);
14            ps.setInt(2,2001);
15            ps.executeUpdate();
16            //2002账户加钱
17            ps.setDouble(1,10000);
18            ps.setInt(2,2002);
19            ps.executeUpdate();
20            conn.commit();//提交事务
21        } catch (Exception e) {
22            if(conn!=null){
23                try {
24                    conn.rollback();//出错时回滚事务
25                } catch (SQLException throwables) {
26                    throwables.printStackTrace();
27                }
28            }
29            e.printStackTrace();
30        }finally {//关闭连接}

JDBC工具类封装

  1. 工具类构造方法一般为私有的,因为工具类一般调用都是静态方法
java
 1public class JdbcUtil {
 2    //工具类构造方法一般都是私有的
 3    private JdbcUtil() {}
 4    static {
 5        try {
 6            //静态代码块中,只要调用该类,则执行注册驱动
 7            Class.forName("com.mysql.jdbc.Driver");
 8        } catch (ClassNotFoundException e) {
 9            e.printStackTrace();
10        }
11    }
12
13    /**
14     * 获取数据库连接对象
15     * @return 连接对象
16     */
17    public static Connection getConnection() throws Exception{
18        return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata?useSSL=false&characterEncoding=utf-8", "root", "123456");
19    }
20
21    /**
22     * 关闭资源
23     * @param conn 连接对象
24     * @param stat 数据库操作对象
25     * @param res 结果集
26     */
27    public static void close(Connection conn, Statement stat, ResultSet res){
28        if (res!=null){
29            try {
30                res.close();
31            } catch (SQLException throwables) {
32                throwables.printStackTrace();
33            }
34        }
35        if (stat!=null){
36            try {
37                stat.close();
38            } catch (SQLException throwables) {
39                throwables.printStackTrace();
40            }
41        }
42        if (conn!=null){
43            try {
44                conn.close();
45            } catch (SQLException throwables) {
46                throwables.printStackTrace();
47            }
48        }
49    }
50    public static void close(Connection conn, Statement stat){
51        if (stat!=null){
52            try {
53                stat.close();
54            } catch (SQLException throwables) {
55                throwables.printStackTrace();
56            }
57        }
58        if (conn!=null){
59            try {
60                conn.close();
61            } catch (SQLException throwables) {
62                throwables.printStackTrace();
63            }
64        }
65    }
66}
使用滚轮缩放
按住拖动