JDBC

概念:

Java DataBase Connectivity Java 数据库连接, Java语言操作数据库

JDBC本质:

其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

JDBC是Java访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用JDBC接口中的方法即可,数据库驱动由数据库厂商提供

使用JDBC的好处:

  1. 程序员如果要开发访问数据库的程序,只需要会调用JDBC接口中的方法即可,不用关注类是如何实现的。
  2. 使用同一套Java代码,进行少量的修改就可以访问其他JDBC支持的数据库

使用JDBC开发使用到的包:

JDBC的核心API

快速入门:

步骤:

  1. 导入驱动jar包mysql-connector-java-5.1.37-bin.jar

    • 复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录

    • 右键–>Add As Library

  1. 注册驱动

  2. 获取数据库连接对象Connection

  3. 定义sql

  4. 获取执行sql语句的对象 Statement

  5. 执行sql,接受返回结果

  6. 处理结果

  7. 释放资源

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1. 导入驱动jar包
//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";
//5.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//6.执行sql
int count = stmt.executeUpdate(sql);
//7.处理结果
System.out.println(count);
//8.释放资源
stmt.close();
conn.close();

详解各个对象:

1. DriverManager:驱动管理类

DriverManager作用:

  1. 管理和注册驱动
  2. 创建数据库的连接

类中的方法:

使用JDBC连接数据库的四个参数:

连接数据库的URL地址格式:

MySQL写法:

1. 1 注册驱动:告诉程序该使用哪一个数据库驱动jar

1
static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。

写代码使用:Class.forName("com.mysql.jdbc.Driver");
通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块

1
2
3
4
5
6
7
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}

注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。

1.2 获取数据库连接:

方法:

1
static Connection getConnection(String url, String user, String password)

参数:

  • url:指定连接的路径

    语法jdbc:mysql://ip地址(域名):端口号/数据库名称

    例子jdbc:mysql://localhost:3306/db3

    细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称

  • user:用户名
  • password:密码

2. Connection:数据库连接对象

Connection作用:

Connection接口,具体的实现类由数据库的厂商实现,代表一个连接对象

Connection方法:

  1. 获取执行sql 的对象
    • Statement createStatement()
    • PreparedStatement prepareStatement(String sql)
  2. 管理事务:
    • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
    • 提交事务:commit()
    • 回滚事务:rollback()

3. Statement:执行sql的对象

JDBC访问数据库的步骤

  1. 注册和加载驱动(可以省略)
  2. 获取连接
  3. Connection获取Statement对象
  4. 使用Statement对象执行SQL语句
  5. 返回结果集
  6. 释放资源

Statement作用:

代表一条语句对象,用于发送SQL语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。

Statement中的方法:

  1. boolean execute(String sql):可以执行任意的sql 了解

  2. int executeUpdate(String sql):执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句

    返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功

    返回值>0的则执行成功,反之,则失败。

  3. ResultSet executeQuery(String sql):执行DQL(select)语句

释放资源

  1. 需要释放的对象:ResultSet结果集Statement语句Connection连接
  2. 释放原则:先开的后关,后开的先关。ResultSet->Statement -> Connection
  3. 放在哪个代码块中:finally块

执行DML操作

需求:

account表 添加一条记录,主键是自动增长

步骤:
  1. 创建连接对象
  2. 创建Statement语句对象
  3. 执行SQL语句:executeUpdate(sql)
  4. 返回影响的行数
  5. 释放资源
实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package src.com.uestc.jdbc;
import java.sql.*;
/**
* account表 添加一条记录 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.获取连接对象
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/db3","root","287216");
//3.创建sql语句
String sql="insert into account (name,balance) values('刘飞',2000)";
//4.创建statement对象
stmt=conn.createStatement();
//5.执行sql
int count=0;
//6.处理结果
count= stmt.executeUpdate(sql);
if(count>0){
System.out.println("添加成功");
}else{
System.out.println("添加失败");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//7. 释放资源
//避免空指针异常
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}

4. ResultSet:结果集对象,封装查询结果

作用:

封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。

接口中的方法:

boolean next():

游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),

如果是,则返回false,如果不是则返回true

getXxx(参数):获取数据
  • Xxx:代表数据类型 如: int getInt() , String getString()
  • 参数:
    1. int:代表列的编号,从1开始 如: getString(1)
    2. String:代表列名称。 如: getDouble("balance")

注意:

使用步骤:

  1. 游标向下移动一行
  2. 判断是否有数据
  3. 获取数据

常用数据类型转换表

执行DQL操作

需求1:

确保数据库中有3条以上的记录,查询所有的学员信息

步骤:
  1. 得到连接对象
  2. 得到语句对象
  3. 执行SQL语句得到结果集ResultSet对象
  4. 循环遍历取出每一条记录
  5. 输出的控制台上
  6. 释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package src.com.uestc.jdbc;
import java.sql.*;
/**
* account表查询记录
*/
public class JdbcDemo03 {
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/db3","root","287216");
//3.创建sql语句
String sql="select * from account";
//4.通过连接获取statement对象
stmt=conn.createStatement();
//5.执行sql获取结果集
rs=stmt.executeQuery(sql);
//6.处理数据
while(rs.next()){
int id=rs.getInt("id");
String name=rs.getString("name");
Double balance=rs.getDouble(3);
System.out.println(id+"---"+name+":"+balance);
}
//7.释放资源
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch(SQLException e){
e.printStackTrace();
}
finally {
try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(stmt!=null){
stmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
需求2:

定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。

步骤:
  1. 定义Employee
  2. 定义方法public List<Employee> findAll(){}
  3. 实现方法select * from emp;
实现
  1. 定义Employee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package src.com.uestc.jdbc;

import java.util.Date;

public class Employee {
private int id;
private String ename;
private int job_id;
private int mgr;
private Date joindate;
private double salary;
private double bounds;
private int dept_id;
public Employee() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getJob_id() {
return job_id;
}
public void setJob_id(int job_id) {
this.job_id = job_id;
}
public int getMgr() {
return mgr;
}
public void setMgr(int mgr) {
this.mgr = mgr;
}
public Date getJoindate() {
return joindate;
}
public Employee(int id, String ename, int job_id, int mgr, Date joindate, double salary, double bounds, int dept_id) {
this.id = id;
this.ename = ename;
this.job_id = job_id;
this.mgr = mgr;
this.joindate = joindate;
this.salary = salary;
this.bounds = bounds;
this.dept_id = dept_id;
}
public void setJoindate(Date joindate) {
this.joindate = joindate;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getBounds() {
return bounds;
}
public void setBounds(double bounds) {
this.bounds = bounds;
}
public int getDept_id() {
return dept_id;
}
public void setDept_id(int dept_id) {
this.dept_id = dept_id;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", ename='" + ename + '\'' +
", job_id=" + job_id +
", mgr=" + mgr +
", joindate=" + joindate +
", salary=" + salary +
", bounds=" + bounds +
", dept_id=" + dept_id +
'}';
}
}
  1. 定义方法public List<Employee> findAll(){}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package src.com.uestc.jdbc;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
*/
public class JdbcDemo04 {
public List<Employee> findAll(){
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
List<Employee> emp_list=new ArrayList();
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建数据库连接connection对象
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root","287216");
//3.定义sql语句
String sql="select * from emp";
//4. 使用数据库连接对象创建statement语句对象
stmt=conn.createStatement();
//5.执行sql语句
rs=stmt.executeQuery(sql);
//6.获得结果集并封装对象
while(rs.next()){
Employee e=new Employee();
e.setId(rs.getInt("id"));
e.setEname(rs.getString("ename"));
e.setJob_id(rs.getInt("job_id"));
e.setMgr(rs.getInt("mgr"));
e.setJoindate(rs.getDate("joindate"));
e.setSalary(rs.getDouble("salary"));
e.setBounds(rs.getDouble("bonus"));
e.setDept_id(rs.getInt("dept_id"));
emp_list.add(e);
}
//打印结果
for(Employee e:emp_list){
System.out.println(e);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
} finally {
//7.释放资源
try {
if(rs!=null){
rs.close();
}
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

}

结果:

5. PreparedStatement:执行sql的对象

SQL注入问题

问题:当我们输入以下密码,我们发现我们账号和密码都不对竟然登录成功了

1
2
3
4
5
6
请输入用户名:
newboy
请输入密码:
a' or '1'='1
select * from user where name='newboy' and password='a' or '1'='1'
登录成功,欢迎您:newboy

问题分析:

1
2
3
4
5
select * from user where name='newboy' and password='a' or '1'='1'
name='newboy' and password='a' 为假
'1'='1'
相当于
select * from user where true; 查询了所有记录

解决sql注入问题:使用PreparedStatement对象来解决

概念: PreparedStatement

PreparedStatement是Statement接口的子接口,继承于父接口中所有的方法。它是一个预编译的SQL语句

PreparedSatement的执行原理

步骤:

  1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar

  2. 注册驱动

  3. 获取数据库连接对象 Connection

  4. 定义sql

    注意:sql的参数使用作为占位符。 如:select * from user where username = ? and password = ?;

  5. 获取执行sql语句的对象

    1
    PreparedStatement  Connection.prepareStatement(String sql)
  6. 设置实际参数:setXxx(占位符的位置, 真实的值)

    注意:parameterIndex1开始

  7. 执行sql,接受返回结果,不需要传递sql语句

  8. 处理结果

  9. 释放资源

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.uestc.jdbc;
import com.uestc.utils.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
/**
* 需求:1.通过键盘输入用户名和密码
* 2.判断用户是否登录
*/
public class JDBCDemo06 {
/**
* 登录方法
*/
public static boolean login(String username, String password){
if(username== null && password==null){
return false;
}
//连接数据库判断是否登录成功
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try{
//获取数据库连接对象
conn=JDBCUtils.getConnection();
//定义sql语句
String sql="select * from USER WHERE username=? AND password=?";
//获取statement语句对象
pstmt=conn.prepareStatement(sql);
//设置参数
pstmt.setString(1, username);
pstmt.setString(2, password);
//执行sql语句
rs=pstmt.executeQuery();
//判断
return rs.next();
}catch (SQLException e){
e.printStackTrace();
}finally {
JDBCUtils.close(conn,pstmt,rs);
}
return false;
}
public static void main(String[] args) {
//1.键盘录入,接收用户名和密码
Scanner in=new Scanner(System.in);
System.out.println("请输入用户名:");
String username=in.next();
System.out.println("请输入密码:");
String password=in.next();
boolean islogin=JDBCDemo06.login(username,password);
if(islogin){
System.out.println("登录成功");
}else{
System.out.println("用户名或者密码错误" );
}
}

}

PreparedSatement的好处

  1. prepareStatement()会先将SQL语句发送给数据库预编译。PreparedStatement会引用着预编译后的结果。可以多次传入不同的参数给PreparedStatement对象并执行。减少SQL编译次数,提高效率。
  2. 安全性更高,没有SQL注入的隐患。
  3. 提高了程序的可读性

注意:后期都会使用PreparedStatement来完成增删改查的所有操作

抽取JDBC工具类 : JDBCUtils

目的:简化书写

需求

上面写的代码中出现了很多重复的代码,可以把这些公共代码抽取出来

创建类JdbcUtil包含3个方法

  1. 可以把几个字符串定义成常量:用户名,密码,URL,驱动类
  2. 得到数据库的连接:getConnection()
  3. 关闭所有打开的资源:
    • close(Connection conn, Statement stmt)
    • close(Connection conn, Statement stmt, ResultSet rs)

分析:

  1. 注册驱动也抽取

  2. 抽取一个方法获取连接对象

    • 需求:不想传递参数(麻烦),还得保证工具类的通用性。

    • 解决:

      配置文件:jdbc.properties

      1
      2
      3
      4
      url=jdbc:mysql://localhost:3306/db3
      user=root
      password=287216
      driver=com.mysql.jdbc.Driver
  3. 抽取一个方法释放资源

    代码实现

  • 首先新建jdbc.properties文件

    1
    2
    3
    4
    url=jdbc:mysql://localhost:3306/db2
    user=root
    password=287216
    driver=com.mysql.jdbc.Driver
  • 然后创建JDBCUtils工具类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    package com.uestc.utils;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.net.URL;
    import java.sql.*;
    import java.util.Properties;
    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("url");
    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();
    }
    }

    /**
    * 获取连接
    * @return 连接对象
    */
    public static Connection getConnection(){
    Connection conn=null;
    try {
    //2.获取数据库连接对象
    conn= DriverManager.getConnection(url,user,password);
    return conn;
    } catch (SQLException e) {
    e.printStackTrace();
    }finally {
    return conn;
    }
    }
    public static void close(Connection conn, Statement stmt){
    try {
    if(stmt!=null){
    stmt.close();
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    try {
    if(conn!=null){
    conn.close();
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    public static void close(Connection conn, Statement stmt, ResultSet rs){
    try {
    if(rs!=null){
    rs.close();
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    try {
    if(stmt!=null){
    stmt.close();
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    try {
    if(conn!=null){
    conn.close();
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }

    }

示例1:使用JDBCUtil 查询所有用户并封装对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.uestc.jdbc;
import com.uestc.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.sql.Statement;

/**
* 演示JdbcUtil工具类
*/
public class JdbcDemo05 {
public static List<Employee> findAll() {
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
List<Employee> emp_list=new ArrayList<>();

try{

//1.获取数据库连接对象
conn=JDBCUtils.getConnection();
//2.定义sql语句
String sql="select * from emp";
//3.创建statement对象
stmt=conn.createStatement();
//4.执行sql
rs=stmt.executeQuery(sql);
//5.封装对象
while(rs.next()){
Employee e=new Employee();
e.setId(rs.getInt("id"));
e.setEname(rs.getString("ename"));
e.setJob_id(rs.getInt("job_id"));
e.setMgr(rs.getInt("mgr"));
e.setJoindate(rs.getDate("joindate"));
e.setSalary(rs.getDouble("salary"));
e.setBounds(rs.getDouble("bonus"));
e.setDept_id(rs.getInt("dept_id"));
emp_list.add(e);

}
return emp_list;

}catch(SQLException e){
e.printStackTrace();
}finally {
//6.关闭连接
JDBCUtils.close(conn,stmt,rs);
}

return emp_list;
}
public static void main(String[] args) {
List<Employee> list=JdbcDemo05.findAll();
System.out.println(list.size());
for(Employee e:list){
System.out.println(e);
}
}
}

示例2:用户登陆

需求:
  1. 通过键盘录入用户名和密码
  2. 判断用户是否登录成功
    • select * from user where username = “” and password = “”;
    • 如果这个sql有查询结果,则成功,反之,则失败
步骤:
  1. 得到用户从控制台上输入的用户名和密码来查询数据库
  2. 写一个登录的方法
  3. 通过工具类得到连接
  4. 创建语句对象,使用拼接字符串的方式生成SQL语句
  5. 查询数据库,如果有记录则表示登录成功,否则登录失败
  6. 释放资源
实现
  1. 创建数据库表 user

    1
    2
    3
    4
    5
    6
    7
    8
    	CREATE TABLE USER(
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(32),
    PASSWORD VARCHAR(32)

    );
    INSERT INTO USER VALUES(NULL, '张三',123456);
    INSERT INTO USER VALUES(NULL, '李四',287216);
  1. 创建登录的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    package com.uestc.jdbc;
    import com.uestc.utils.JDBCUtils;
    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 boolean login(String username, String password){
    if(username== null && password==null){
    return false;
    }
    //连接数据库判断是否登录成功
    Connection conn=null;
    Statement stmt=null;
    ResultSet rs=null;
    try{
    //获取数据库连接对象
    conn=JDBCUtils.getConnection();
    //获取statement语句对象
    stmt=conn.createStatement();
    //定义sql语句
    String sql="select * from USER WHERE username='"+username+"' AND password='"+password+"'";
    //执行sql语句
    rs=stmt.executeQuery(sql);
    //判断
    return rs.next();
    }catch (SQLException e){
    e.printStackTrace();
    }finally {
    JDBCUtils.close(conn,stmt,rs);
    }
    return false;
    }
    public static void main(String[] args) {
    //1.键盘录入,接收用户名和密码
    Scanner in=new Scanner(System.in);
    System.out.println("请输入用户名:");
    String username=in.next();
    System.out.println("请输入密码:");
    String password=in.next();
    boolean islogin=JDBCDemo06.login(username,password);
    if(islogin){
    System.out.println("登录成功");
    }else{
    System.out.println("用户名或者密码错误" );
    }
    }
    }

JDBC控制事务:

事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

API介绍

开发步骤

  1. 获取连接
  2. 开启事务
  3. 获取到PreparedStatement
  4. 使用PreparedStatement执行两次更新操作
  5. 正常情况下提交事务
  6. 出现异常回滚事务
  7. 最后关闭资源

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.uestc.jdbc;
import com.uestc.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 事务操作
* 没有异常,提交事务,出现异常回滚事务
public static
*/
public class JdbcDemo07 {
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- ? where name=?";
//2.2 李四+500
String sql2="update account set balance=balance+ ? where name=?";
//3.获取prepareStatement
pstmt1=conn.prepareStatement(sql1);
pstmt2=conn.prepareStatement(sql2);
//4.设置参数
pstmt1.setDouble(1,500);
pstmt1.setString(2,"张三");

pstmt2.setDouble(1,500);
pstmt2.setString(2,"李四");

//5.执行sql
pstmt1.executeUpdate();

//手动制造异常
int i=3/0;
pstmt2.executeUpdate();
//事务提交
conn.commit();
}catch (Exception e){
//事务回滚
if(conn!=null){
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}finally {
JDBCUtils.close(conn,pstmt1);
JDBCUtils.close(null,pstmt2);
}
}
}

数据库连接池

概念

其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

好处:

  1. 节约资源
  2. 用户访问高效

实现:

一般我们不去实现它,有数据库厂商来实现

  1. C3P0:数据库连接池技术
  2. Druid:数据库连接池实现技术,由阿里巴巴提供的

标准接口:DataSource javax.sql包下的

方法:

  • 获取连接getConnection()
  • 归还连接Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

C3P0:数据库连接池技术

步骤:
  1. 导入jar包 (两个) c3p0-0.9.5.2.jarmchange-commons-java-0.2.12.jar

    注意不要忘记导入数据库驱动jar包

  2. 定义配置文件:

    • 名称: c3p0.properties 或者 c3p0-config.xml
    • 路径:直接将文件放在src目录下即可。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <c3p0-config>
    <!-- 使用默认的配置读取连接池对象 -->
    <default-config>
    <!-- 连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property>
    <property name="user">root</property>
    <property name="password">287216</property>

    <!-- 连接池参数 -->
    <!-- 初始化申请的连接数量 -->
    <property name="initialPoolSize">5</property>
    <!-- 最大的连接数量 -->
    <property name="maxPoolSize">10</property>
    <!-- 超时时间 -->
    <property name="checkoutTimeout">3000</property>
    </default-config>

    <named-config name="otherc3p0">
    <!-- 连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>

    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">8</property>
    <property name="checkoutTimeout">1000</property>
    </named-config>
    </c3p0-config>
  3. 创建核心对象 数据库连接池对象 ComboPooledDataSource

  4. 获取连接: getConnection

  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.uestc.datasource.c3p0;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    public class C3P0Demo1 {
    public static void main(String[] args) {
    //1.创建数据库连接池对象, 这里不传参表示使用默认的c3p0配置
    DataSource ds=new ComboPooledDataSource();
    Connection conn=null;
    //2.获取连接对象
    try {
    conn=ds.getConnection();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    //3.打印
    System.out.println(conn);
    }
    }

Druid:数据库连接池实现技术,由阿里巴巴提供的

步骤:
  1. 导入jar包 druid-1.0.9.jar
  2. 定义配置文件:
    • properties形式的
    • 可以叫任意名称,可以放在任意目录下
  3. 加载配置文件。Properties
  4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
  5. 获取连接:getConnection
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.uestc.datasource.druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/**
* Druid演示
*/
public class DruidDemo1 {
public static void main(String[] args) throws Exception{
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties pro=new Properties();
InputStream is=DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//4.获取连接池对象
DataSource ds=DruidDataSourceFactory.createDataSource(pro);
//5.获取连接
Connection conn=ds.getConnection();
System.out.println(conn);
}
}

定义工具类

步骤
  1. 定义一个类 JDBCUtils
  2. 提供静态代码块加载配置文件,初始化连接池对象
  3. 提供方法
    1. 获取连接方法:通过数据库连接池获取连接
    2. 释放资源
    3. 获取连接池的方法
实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.uestc.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
* Druid连接池的工具类
*/
public class JDBCUtils {
//1.定义成员变量 DataSouce 连接池对象
private static DataSource ds;
static{
try {
//1.加载配置文件
Properties pro=new Properties();
InputStream is=JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
ds=DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static void close(ResultSet rs, Statement stmt, Connection conn){
try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(stmt!=null){
stmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}

try {
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(Statement stmt, Connection conn){
close(null,stmt,conn);
}
/**
* 获取连接池对象
* @return
*/
public static DataSource getDataSource(){
return ds;
}
}
工具类测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.uestc.datasource.druid;
import com.uestc.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 使用druid工具类
*/
public class DruidDemo2 {
public static void main(String[] args) {
/**
* 完成给account添加一条记录
*/
Connection conn=null;
PreparedStatement pstmt=null;
try {
//1.获取连接
conn=JDBCUtils.getConnection();
//2.定义sql
String sql="insert into account VALUES(null,?,?)";
//3.获取prepareStatement对象
pstmt=conn.prepareStatement(sql);
//4.设置参数的值
pstmt.setString(1,"老王");
pstmt.setDouble(2,4000);
//5.执行sql
int count=pstmt.executeUpdate();
if(count>0){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(pstmt,conn);
}

}
}

Spring JDBC

概念

Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发

步骤:

  1. 导入jar

  2. 创建JdbcTemplate对象。依赖于数据源DataSource

    1
    JdbcTemplate template = new JdbcTemplate(ds);
  3. 调用JdbcTemplate的方法来完成CRUD的操作

    • update():执行DML语句。增、删、改语句

    • queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合

      注意:这个方法查询的结果集长度只能是1

    • queryForList():查询结果将结果集封装为list集合

      注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中

    • query():查询结果,将结果封装为JavaBean对象

      query的参数:RowMapper

      • 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
      • new BeanPropertyRowMapper<类型>(类型.class)
    • queryForObject:查询结果,将结果封装为对象

    • 一般用于聚合函数的查询

    案例:

需求:

  1. 修改1号数据的 salary 为 10000
  2. 添加一条记录
  3. 删除刚才添加的记录
  4. 查询id为1的记录,将其封装为Map集合
  5. 查询所有记录,将其封装为List
  6. 查询所有记录,将其封装为Emp对象的List集合
  7. 查询总记录数

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package com.uestc.jdbctemplate;
import com.uestc.domain.Emp;
import com.uestc.jdbc.Employee;
import com.uestc.utils.JDBCUtils;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class JdbcTemplateDemo2 {
//1.创建JdbcTemplate对象
private JdbcTemplate jdbcTemplate=new JdbcTemplate(JDBCUtils.getDataSource());
//Junit单元测试,可以让方法独立执行
/**
* 修改1号数据的 salary 为 10000
*/
@Test
public void test1(){

//2.定义sql
String sql="update emp set salary=10000 where id=1001";
//3.执行sql
int count=jdbcTemplate.update(sql);
System.out.print(count);
}
/**
* 添加一条记录
*/
@Test
public void test2(){

//2.定义sql
String sql="insert into emp(id,ename,dept_id) values(?,?,?)";
//3.执行sql
int count=jdbcTemplate.update(sql,1015,"刘飞",10);
System.out.print(count);
}
/**
*删除刚才添加的记录
*/
@Test
public void test3(){

//2.定义sql
String sql="delete from emp where id=?";
//3.执行sql
int count=jdbcTemplate.update(sql,1015);
System.out.print(count);
}
/**
*查询id为1001的记录,将其封装为Map集合
*/
@Test
public void test4(){

//2.定义sql
String sql="select * from emp where id=?";
//3.执行sql
Map<String,Object> map= jdbcTemplate.queryForMap(sql,1001);
System.out.print(map);
}

/**
* 查询所有记录,将其封装为List
*/

@Test
public void test5(){

//2.定义sql
String sql="select * from emp ";
//3.执行sql
List<Map<String,Object>> list= jdbcTemplate.queryForList(sql);
for(Map map:list){
System.out.println(map);
}
}

/**
* 查询所有记录,将其封装为Emp对象的List集合
*/
@Test
public void test6(){

//2.定义sql
String sql="select * from emp ";
//3.执行sql
List<Emp> list= jdbcTemplate.query(sql, new RowMapper<Emp>() {

@Override
public Emp mapRow(ResultSet rs, int i) throws SQLException {
Emp e=new Emp();
e.setId(rs.getInt("id"));
e.setEname(rs.getString("ename"));
e.setJob_id(rs.getInt("job_id"));
e.setMgr(rs.getInt("mgr"));
e.setJoindate(rs.getDate("joindate"));
e.setSalary(rs.getDouble("salary"));
e.setBounds(rs.getDouble("bonus"));
e.setDept_id(rs.getInt("dept_id"));

return e;
}
});
for(Emp emp:list){
System.out.println(emp);
}
}

@Test
public void test7(){

//2.定义sql
String sql="select * from emp ";
//3.执行sql
List<Emp> list= jdbcTemplate.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
for(Emp emp:list){
System.out.println(emp);
}
}
/**
* 查询总记录数
*/

@Test
public void test8(){

//2.定义sql
String sql="select count(*) from emp ";
//3.执行sql
Long total= jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(total);
}
}