一、JDBC 快速入门
1.1 什么是 JDBC?
Java数据库连接,(Java Database Connectivity,简称 JDBC )是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。 —— 来源于百度词条
1.2 为什么要学习 JDBC?
我们存储数据总不能全部存进 文件里,然后使用 FileInputStream 和 FileOutPutStream 进行读和写的操作把,这个时候数据库就来了,那么什么是数据库呢?(数据库:即组织,存储 和 管理数据的仓库)。这样有了数据库,我们就可以把结构化的数据存储进数据库中,有了数据库这个东西,接下来我们就可以使用 JDBC 操作数据库啦!
1.3 学习 JDBC 之前需要有哪些准备知识呢?
- 使用 JDBC 得先学习什么是数据库
- 并且会熟练使用 sql 语句进行 CRUD 操作
- 掌握一种关系型数据库的使用(mysql)
- 了解 JDBC 的基本步骤
二、编写你的第一个 JDBC 程序
2.1 导入一个外部 jar 包
我们连接 mysql 数据库,所以需要导入 mysql 的驱动包,我的 mysql 版本是 5.7 的,所以使用 版本第一点的 驱动即可。
这个 jar 包是从网上下载下来的,它是由 数据库开发商提供的,专门用来连接 java 的驱动包,这个是必不可少的。
2.2 编写一个简单的 jdbc 程序
我这个程序的作用是 查询 bank 数据库中的,user 表
import java.sql.*;
public class DBUTIL {
private static final String URL = "jdbc:mysql://localhost:3306/bank";
private static final String USERNAME = "root";
private static final String PASSWORD = "root";
/**
* 对数据库中的数据进行增删改查 CRUD
* sql: insert、delete、update、select
*通过 java 程序来操作数据库中的数据 jdbc
* 在 java 中写 sql,java “将写好的 sql 交给数据库运行” 从而操作数据
* 重点:将写好的 sql 交给数据库运行
* */
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1. 加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2. 获取数据库的连接
Connection coon = DriverManager.getConnection(URL,USERNAME,PASSWORD);
//3. 通过数据库的连接操作数据库,实现增删改查
Statement stmt = (Statement) coon.createStatement();
// 查用 executeQuery,其它用 execute
ResultSet rs = stmt.executeQuery("select * from user");//返回 ResultSet 对象
/**
* 1. 加载数据的驱动(先决条件)
* 2. 将当前的 java 程序与数据库建立连接
* 3. 将 sql 交给数据库运行
* 4. 处理结果
* 5. 关闭资源(首尾)
* */
//打印数据
System.out.println("username password status phone registertime");
while(rs.next()) {
//返回字符串, 两种查询的方式
// System.out.println(rs.getString("username")+" "+rs.getString("password"));
System.out.println(rs.getString(1)+ " "+ rs.getString(2)+" "+rs.getInt(3)+ " "+ rs.getInt(4)+" "+rs.getTimestamp(5));
}
rs.close();
stmt.close();
coon.close();
}
}
三、JDBC 的封装
3.1 封装等级(一级)
此等级需要用户编写重要的 SQL 语句即可完成
import java.sql.*;
public class BaseDao {
private String Driver = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/bank?useUnicode=true&characterEncoding=utf8";
private static final String USERNAME = "root";
private static final String PASSWORD = "root";
private Connection con = null;
// 获取连接
public PreparedStatement getConnect(String sql) throws SQLException {
PreparedStatement ps = null;
try {
Class.forName(Driver);
con = DriverManager.getConnection(URL,USERNAME,PASSWORD);
ps = con.prepareStatement(sql);
} catch (Exception e) {
e.printStackTrace();
con.rollback();
}
return ps;
}
// 关闭连接
public void colesd(PreparedStatement ps, ResultSet set) throws SQLException {
if (ps!=null) {
ps.close();
}
if (set!=null) {
set.close();
}
if (con!=null) {
con.close();
}
}
}
3.2 封装等级(二级)
完成 增删改 和 查的封装
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Gorit
* @date 2019年12月13日
* @Task JDBC 使用 BaseDao 进行封装
* @next 使用 jdbc.properties 进行全局封装
* @资料:参考 11-25 的资料
* */
public class BaseDao {
//导入 java.sql 包下的类
protected Connection conn = null;
protected PreparedStatement pstmt = null;
protected ResultSet rs = null;
//1.得到连接对象
public boolean getConn() {
boolean flag = false;
//1. 加载驱动 com.mysql.jdbc.Driver
try {
//jdbc.driver = com.mysql.jdbc.Driver
//jdbc.url = jdbc:mysql://localhost:3306/bank
//jdbc.username=root
//jdbc.password=root
Class.forName("com.mysql.jdbc.Driver");
//2. 创建连接对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bank?userUnicode=true&characterEncoding=utf8","root","root");
flag = true;//标记
} catch (ClassNotFoundException | SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
return flag;
}
// 2 executeUpdate--增删改 sql 参数不同
public int executeUpdate(String sql, Object[] params) {
int result = 0;
if (getConn()) {//连接成功
try {
pstmt = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
result = pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //得到pstmt对象
}
return result;
}
// 3 executeQuery 语句查询
public ResultSet executeQuery(String sql, Object[] params) {
if (getConn()) { //连接成功
try {
pstmt = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
rs = pstmt.executeQuery(); //执行查询工作
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
return rs;
}
//4 释放资源,关闭连接
public void closeResource() {
//按顺序关闭
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
四、C3P0以及Druid数据库连接池
4.1什么是数据库连接池?
概念:其实就是一个容器(集合),存放数据库连接的容器。 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户访问数据库时,从容器中获取连接对象,用 户访问完后,会将连接对象还给容器
4.2C3P0连接池
C3P0配置文件的注意事项
- 名称:c3p0.properties或者c3p0-config.xml
- 路径:直接将文件放在src目录下
C3P0的基本用法
//1.创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
//2. 获取连接对象
Connection conn = ds.getConnection();
4.3Durid连接池(常用)
利用Druid进行jdbc封装
package per.myself.utils;
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;
public class JDBCUtils {
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();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//释放资源
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();
// }
// }
close(null,stmt,conn);
}
public static void close(ResultSet res, Statement stmt, Connection conn) {
if(res!=null){
try {
res.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;
}
}
五、Spring JDBC:JDBC Template
5.1JDBC Template方法的CRUD操作
- update():执行DML语句。增、删、改语句
- queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
注意:这个方法查询的结果集长度只能是1
- queryForList():查询结果将结果集封装为list集合
注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
- query():查询结果,将结果封装为JavaBean对象
query的参数:RowMapper
一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
new BeanPropertyRowMapper<类型>(类型.class)queryForObject:查询结果,将结果封装为对象
一般用于聚合函数的查询
5.2JDBC Template实现对数据库的操作
这里是对tb_account进行操作,表的数据有id,userName,password
package per.myself.jdbctemplate;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import per.myself.entity.Account;
import per.myself.utils.JDBCUtils;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class JdbcTemplateDemo002 {
//Junit单元测试,可以让方法独立执行
//1. 获取JDBCTemplate对象
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 1. 修改1号数据的 salary 为 10000
*/
@Test
public void test1(){
//2. 定义sql
String sql = "update tb_account set password = 10000 where id = 3";
//3. 执行sql
int count = template.update(sql);
System.out.println(count);
}
/**
* 2. 添加一条记录
*/
@Test
public void test2(){
String sql = "insert into tb_account values(?,?,?)";
int count = template.update(sql, null, "郭靖", "asdsa");
System.out.println(count);
}
/**
* 3.删除刚才添加的记录
*/
@Test
public void test3(){
String sql = "delete from tb_account where id = ?";
int count = template.update(sql, 2);
System.out.println(count);
}
/**
* 4.查询id为1001的记录,将其封装为Map集合
* 注意:这个方法查询的结果集长度只能是1
*/
@Test
public void test4(){
String sql = "select * from tb_account where id = ? ";
Map<String, Object> map = template.queryForMap(sql, 1);
System.out.println(map);
//{id=1001, ename=孙悟空, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=20}
}
/**
* 5. 查询所有记录,将其封装为List
*/
@Test
public void test5(){
String sql = "select * from tb_account";
List<Map<String, Object>> list = template.queryForList(sql);
for (Map<String, Object> stringObjectMap : list) {
System.out.println(stringObjectMap);
}
}
/**
* 6. 查询所有记录,将其封装为Emp对象的List集合
*/
@Test
public void test6(){
String sql = "select * from tb_account";
List<Account> list = template.query(sql, new RowMapper<Account>() {
@Override
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account emp = new Account();
int id = rs.getInt("id");
String userName = rs.getString("userName");
String password = rs.getString("password");
emp.setId(id);
emp.setUserName(userName);
emp.setPassword(password);
return emp;
}
});
for (Account acc : list) {
System.out.println(acc);
}
}
/**
* 6. 查询所有记录,将其封装为Emp对象的List集合
*/
@Test
public void test6_2(){
String sql = "select * from tb_account";
List<Account> list = template.query(sql, new BeanPropertyRowMapper<Account>(Account.class));
for (Account acc : list) {
System.out.println(acc);
}
}
/**
* 7. 查询总记录数
*/
@Test
public void test7(){
String sql = "select count(id) from tb_account";
Long total = template.queryForObject(sql, Long.class);
System.out.println(total);
}
}