JDBC入门

概念

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

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

快速入门

  • 步骤:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
    1.复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
    2.右键-->Add As Library
    2. 注册驱动
    3. 获取数据库连接对象 Connection
    4. 定义sql
    5. 获取执行sql语句的对象 Statement
    6. 执行sql,接受返回结果
    7. 处理结果
    8. 释放资源
  • 代码实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //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();

组成对象

DriverManager

:驱动管理对象

  1. 注册驱动:告诉程序该使用哪一个数据库驱动jar
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。 
    写代码使用: Class.forName("com.mysql.jdbc.Driver");
    通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
    static {
    try {
    java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
    throw new RuntimeException("Can't register driver!");
    }
    }

    注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。
    已在jar包的META-INF/services/java.sql.Driver文件中定义了
  2. 获取数据库连接:
    1
    2
    3
    4
    5
    6
    7
    8
    * 方法:static Connection getConnection(String url, String user, String password) 
    * 参数:
    * url:指定连接的路径
    * 语法:jdbc:mysql://ip:端口号/数据库名称
    * 例子:jdbc:mysql://localhost:3306/db3
    * 细节:如果连接的是本机3306,可简写为:jdbc:mysql:///数据库名称
    * user:用户名
    * password:密码

Connection

:数据库连接对象

1
2
3
4
5
6
7
1. 获取执行sql 的对象
* Statement createStatement()
* PreparedStatement prepareStatement(String sql)
2. 管理事务:
* 开启事务:setAutoCommit(boolean autoCommit) :默认true自动提交;false手动提交开始事务。
* 提交事务:commit()
* 回滚事务:rollback()

Statement

:执行sql的对象

  1. 执行sql
    1
    2
    3
    4
    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)语句
  2. 练习:
    在这里插入图片描述

ResultSet

:结果集对象,封装查询结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
* boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),
如果是,则返回false,如果不是则返回true
* getXxx(参数):获取数据
* Xxx:代表数据类型 如: int getInt() , String getString()
* 参数:
1. int:代表列的编号,从1开始 如: getString(1)
2. String:代表列名称。 如: getDouble("balance")

* 注意:
* 使用步骤:
1. 游标向下移动一行
2. 判断是否有数据
3. 获取数据

//循环判断游标是否是最后一行末尾。
while(rs.next()){
//获取数据
//6.2 获取数据
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble(3);

System.out.println(id + "---" + name + "---" + balance);
}

PreparedStatement

:执行sql的对象

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
1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
1. 输入用户随便,输入密码:a' or 'a' = 'a
2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'

2. 解决sql注入问题:使用PreparedStatement对象来解决
3. 预编译的SQL:参数使用?作为占位符
4. 步骤:
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语句的对象 PreparedStatement Connection.prepareStatement(String sql)
6. 给?赋值:
* 方法: setXxx(参数1,参数2)
* 参数1:?的位置编号 从1 开始
* 参数2:?的值
7. 执行sql,接受返回结果,不需要传递sql语句
8. 处理结果
9. 释放资源

5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
1. 可以防止SQL注入
2. 效率更高

JDBCUtils

:抽取JDBC工具类

  • src目录下的jdbc.properties
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 加?serverTimezone=UTC避免时区错误 指定字符集防止编码异常
    url=jdbc:mysql:///student?serverTimezone=UTC&characterEncoding=utf-8
    user=root
    password=123456
    # 可省略配置driver,在驱动jar包中已经标注 META-INF/services/java.sql.Driver
    # MySQL5 com.mysql.jdbc.Driver
    # MySQL8 com.mysql.cj.jdbc.Driver
    #driver=com.mysql.jdbc.Driver
    #driver=com.mysql.cj.jdbc.Driver
JDBCUtils.java
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
import java.io.FileReader;
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 resourceURL = classLoader.getResource("jdbc.properties");
/*
String path1 = resourceURL.getPath();//中文,空格等符号会乱码
String path2 = resourceURL.toURI().getPath();//正确
String path3 = URLDecoder.decode(resourceURL.getPath(),"utf8");//正确
*/
String path = resourceURL.toURI().getPath();
//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 (Exception e)
{
e.printStackTrace();
}
}


/**
* 获取连接
*
* @return 连接对象
*/
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();
} 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 (rs != null)
{
try
{
rs.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}

if (stmt != null)
{
try
{
stmt.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}

if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
}

}

事务

MySQL 事务
JDBC控制事务:

1
2
3
4
5
6
7
8
9
10
11
12
13
1. 事务:一个包含多个步骤的业务操作。
如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
2. 操作:
1. 开启事务
2. 提交事务
3. 回滚事务
3. 使用Connection对象来管理事务
* 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
* 在执行sql之前开启事务
* 提交事务:commit()
* 当所有sql都执行完提交事务
* 回滚事务:rollback()
* 在catch中回滚事务

在这里插入图片描述

连接池

简介

  1. 概念:
    1
    2
    3
    其实就是一个容器(集合),存放数据库连接的容器。
    当系统初始化好后,容器被创建,容器中会申请一些连接对象,
    当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
  2. 好处:
    1
    2
    1. 节约资源
    2. 用户访问高效
  3. 实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    1. 标准接口:DataSource   javax.sql包下的
    * 获取连接:getConnection()
    * 归还连接:Connection.close()。
    如果连接对象Connection是从连接池中获取的,
    那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

    2. 一般我们不去实现它,有数据库厂商来实现
    1. C3P0:数据库连接池技术
    2. Druid:数据库连接池实现技术,由阿里巴巴提供的

C3P0(了解)

:数据库连接池技术

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
* 步骤:
1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,
* 不要忘记导入数据库驱动jar包
2. 定义配置文件:
* 名称: c3p0.properties 或者 c3p0-config.xml
* 路径:直接将文件放在src目录下即可。

3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
4. 获取连接: getConnection
* 代码:
//1.创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
//使用指定名称配置
DataSource ds = new ComboPooledDataSource("otherc3p0");
//2. 获取连接对象
Connection conn = ds.getConnection();
c3p0-config.xml
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
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<!-- MySQL5 com.mysql.jdbc.Driver MySQL8 com.mysql.cj.jdbc.Driver -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!-- 加?serverTimezone=UTC避免时区错误 -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/student?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</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.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/student?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>

<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>

在这里插入图片描述

Druid(重要)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1. 步骤:
1. 导入jar包 druid-1.0.9.jar
2. 定义配置文件:
* 是properties形式的
* 可以叫任意名称,可以放在任意目录下
3. 加载配置文件。Properties
4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
5. 获取连接:getConnection
* 代码:
//3.加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//5.获取连接
Connection conn = ds.getConnection();

src目录下的druid.properties

1
2
3
4
5
6
7
8
9
10
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student?serverTimezone=UTC
username=root
password=123456
# 初始化连接数
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
连接池改造JDBCUtils.java
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
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
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.定义成员变量 DataSource
private static DataSource ds ;

static{
try {
//1.加载配置文件
Properties pro = new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2.获取DataSource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException { return ds.getConnection(); }

/**
* 释放资源
* @param stmt
* @param conn
*/
public static void close(Statement stmt,Connection conn){ close(null,stmt,conn); }


/**
* 释放资源
* @param rs
* @param stmt
* @param conn
*/
public static void close(ResultSet rs , Statement stmt, Connection conn){


if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}


if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

if(conn != null){
try {
conn.close();//归还连接
} catch (SQLException e) {
e.printStackTrace();
}
}
}

/**
* 获取连接池方法
*/

public static DataSource getDataSource(){ return ds; }

}