JDBC
概述
可以为多种关系数据库提供统一访问,为开发者屏蔽了一些细节问题
获取数据库链接对象
Connection -> 数据库连接对象
导入驱动包
获取数据库连接对象
1.加载注册驱动:
Driver驱动类:应该加载驱动包中实现Driver接口类的对象
public static void registerDriver(Driver driver):注册驱动
API中,建议使用Class.forName(“com.mysql.jdbc.Driver”);加载字节码对象的时候,会执行这个类的静态代码块.
调用Class.forName不是目的,目的是为了执行com.mysql.jdbc.Driver这个类的静态代码块.
而这个类的静态代码块就是在加载注册驱动
2.获取数据库连接对象
DriverManager驱动管理类:
public static Connection getConnection(String url, String user, String password): 获取数据库连接对象.
JDBC操作模板
1.加载注册驱动
2.获取数据库连接对象
3.生成预编译语句对象
4.执行SQL命令
5.释放资源
相关操作
executeQuery(String sql): 执行DQL操作,返回单个ResultSet对象.
executeUpdate(String sql): 执行DDL和DML操作
DML操作
1 | package me.cscar.dml; |
抽象出JDBCUtil包,复用释放资源代码
1 | public class JDBCUtil { |
预编译语句对象
PreparedStatement对象:又叫做预编译语句对象,是一个包含占位符?的sql模板.
1.PreparedStatement ps= conn.prepareStatement(sql模板);// 传递的是sql模板,不能直接执行.
2.ps.setObject(int parameterIndex, Object x):给占位符?设置值,parameterIndex代表第N个?号,x是具体参数
3.执行sql语句:不能调用父类带参数的方法.
如果直接调用父类的带sql参数方法,会直接将带占位符?的sql模板拿过去执行
1 | public class Insert { |
DQL操作
ResultSet常用的API:
Object getObject(int columnIndex): 根据数据的列的索引获取数据.
columnIndex: 表示第几列的意思,从1开始.
Object getObject(String columnLabel): 根据数据的列名来获取数据.
columnLabel: 表示列名.
boolean next(): 是否有下一行, 如果返回是true,表示已经移动到下一行了.
获取单条数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class TestGet {
public void testGet() throws Exception {
//?表示占位符
String sql = "SELECT * FROM student WHERE id=?";
//注册加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获得数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/javaweb", "root", "admin");
//获取预编译语句对象
PreparedStatement ps = conn.prepareStatement(sql);
//给SQL设置值
ps.setObject(1, 5L);
ResultSet resultSet = ps.executeQuery();
if (resultSet.next()) {
Object obj = resultSet.getObject("name");
System.out.println(obj);
}
JDBCUtil.close(conn, ps);
}
}
获取全部数据,用list装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
32public class TestListAll {
public void testListAll() throws Exception {
List<Student> list = new ArrayList<>();
String sql = "SELECT * FROM student";
//1.加载注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获得连接数据库对象
Connection conn = DriverManager.getConnection("jdbc:mysql:///javaweb", "root", "admin");
//3.获得预编译语句对象
PreparedStatement ps = conn.prepareStatement(sql);
//执行查询
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Student stu = new Student();
long id = rs.getLong("id");
String name = rs.getString("name");
Integer age = rs.getInt("age");
stu.setId(id);
stu.setName(name);
stu.setAge(age);
list.add(stu);
}
System.out.println(list);
JDBCUtil.close(conn, ps);
}
}
DAO规范
使用DAO规范对数据库的增删改查,避免重复代码,直接调用DAO方法
DAO的设计
1.保存方法
void save(Object obj)
把要保存的信息,封装成一个对象,传递给方法.
用来描述数据库表结构的javabean, 是一个特殊的javabean. ---> domain
2.删除方法
void delete(Long id)
根据主键id来删除数据
3.修改方法
void update(Object obj)
把传递过来的新的信息设置到指定的数据库的记录
4.查询单个
Student get(Long id)
把查询数据封装到domain中.
5.查询多个
List<Student> listAll();
使用ArrayList装
DAO的规范
DAO规范,只要有操作数据库的地方,都需要该规范.
主要就是针对包以及类名进行规范.
1.DAO接口.
me.cscar.smis.dao:IXxxDAO ====> Xxx 就是domain
2.DAO接口的实现类.
me.cscar.smis.dao.impl:StudentDAOImpl
3.domain类:
me.cscar.smis.domain:Student
4. 测试类:
me.cscar.smis.test:StudentDAOTest
5. 工具类:
me.cscar.smis.util:StringUtil/JDBCUtil
开发流程
1.创建数据库表
2.根据数据库表来创建domain包以及类.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package me.cscar.refactorpro.domain;
import lombok.*;
import java.math.BigDecimal;
public class Product {
private Long id;
private String productName;
private BigDecimal salePrice;
private BigDecimal cutoff;
}
3.根据domain来创建DAO包以及接口.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
44package me.cscar.refactorpro.dao;
import me.cscar.refactorpro.domain.Product;
import java.util.List;
public interface IProductDAO {
/**
* 增加
*
* @param pro
*/
void save(Product pro);
/**
* 删除
*
* @param id
*/
void delete(Long id);
/**
* 修改
*
* @param pro
*/
void update(Product pro);
/**
* 查询指定
*
* @param id
* @return
*/
Product get(Long id);
/**
* 查询全部
*
* @return
*/
List getAll();
}
4.根据DAO接口来生成实现类.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190package me.cscar.refactorpro.dao.impl;
import me.cscar.refactorpro.dao.IProductDAO;
import me.cscar.refactorpro.domain.Product;
import me.cscar.refactorpro.util.JDBCutil;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ProductDAOImpl implements IProductDAO {
public static ProductDAOImpl getInstance() {
return new ProductDAOImpl();
}
/**
* 增加
*
* @param pro
*/
public void save(Product pro) {
Connection conn = null;
PreparedStatement ps = null;
try {
String sql = "INSERT INTO t_product (productName,salePrice,cutoff) VALUES (?,?,?)";
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
ps.setObject(1, pro.getProductName());
ps.setObject(2, pro.getSalePrice());
ps.setObject(3, pro.getCutoff());
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCutil.close(conn, ps);
}
}
/**
* 删除
*
* @param id
*/
public void delete(Long id) {
Connection conn = null;
PreparedStatement ps = null;
try {
String sql = "DELETE FROM t_product WHERE id = ?";
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
ps.setObject(1, id);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
JDBCutil.close(conn, ps);
}
/**
* 修改
*
* @param pro
*/
public void update(Product pro) {
Connection conn = null;
PreparedStatement ps = null;
try {
String sql = "UPDATE t_product SET productName=?,salePrice=?,cutoff=? WHERE id=?";
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
ps.setObject(1, pro.getProductName());
ps.setObject(2, pro.getSalePrice());
ps.setObject(3, pro.getCutoff());
ps.setObject(4, pro.getId());
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCutil.close(conn, ps);
}
}
/**
* 查询指定
*
* @param id
* @return
*/
public Product get(Long id) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT * FROM t_product WHERE id = ?";
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
ps.setObject(1, id);
rs = ps.executeQuery();
while (rs.next()) {
Product pro = new Product();
String productName = rs.getString("productName");
BigDecimal salePrice = rs.getBigDecimal("salePrice");
BigDecimal cutoff = rs.getBigDecimal("cutoff");
Long proid = rs.getLong("id");
pro.setId(proid);
pro.setProductName(productName);
pro.setSalePrice(salePrice);
pro.setCutoff(cutoff);
return pro;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
JDBCutil.close(conn, ps);
}
throw new RuntimeException("查询错误");
}
/**
* 查询全部
*
* @param pro
* @return
*/
public List getAll() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT * FROM t_product";
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
List<Product> list = new ArrayList<>();
while (rs.next()) {
Product pro = new Product();
String productName = rs.getString("productName");
BigDecimal salePrice = rs.getBigDecimal("salePrice");
BigDecimal cutoff = rs.getBigDecimal("cutoff");
Long proid = rs.getLong("id");
pro.setId(proid);
pro.setProductName(productName);
pro.setSalePrice(salePrice);
pro.setCutoff(cutoff);
list.add(pro);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
JDBCutil.close(conn, ps);
} catch (SQLException e) {
e.printStackTrace();
}
}
throw new RuntimeException("查询出错");
}
}
5.根据测试先行,根据DAO接口生成测试类.完成测试类.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
43package me.cscar.refactorpro.test;
import me.cscar.refactorpro.dao.impl.ProductDAOImpl;
import me.cscar.refactorpro.domain.Product;
import me.cscar.refactorpro.util.JDBCutil;
import org.junit.Test;
import java.math.BigDecimal;
import java.sql.Connection;
import java.util.List;
public class ProductDAOTest {
public void save() {
Product pro = new Product(null, "mac", new BigDecimal("15000"), new BigDecimal("0.9"));
ProductDAOImpl.getInstance().save(pro);
}
public void delete() {
ProductDAOImpl.getInstance().delete(6L);
}
public void update() {
Product newpro = new Product(5L, "suffer", new BigDecimal("14000"), new BigDecimal("0.99"));
ProductDAOImpl.getInstance().update(newpro);
}
public void get() {
Product product = ProductDAOImpl.getInstance().get(4L);
System.out.println(product);
}
public void getAll() {
List all = ProductDAOImpl.getInstance().getAll();
System.out.println(all);
}
}
抽取和完善JDBCutil
新建配置文件,properties1
2
3
4ClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///javaweb
userName=xxx
password=xxx
1 | package me.cscar.refactorpro.util; |
预编译语句对象原理
避免了sql语句字符串拼接.
有的数据库有DBMS有缓冲区,预编译语句对象可以提交效率. mysql不支持
DBMS
1.安全检查
2.语义分析
检查语句在缓存中是否存在
3.编译SQL
4.执行SQL
有缓存区会存储编译好的sql模板,?
使用预编译语句对象可以防止SQL注入
其他问题
jdbc驱动8.0以上版本时区,少一天
连接数据库的url加上1
serverTimezone=Asia/Shanghai