一、JDBC基本概念和下载
JDBC(Java DataBase Connectivity),通俗来讲就是用java语言操作数据库
- 本质
sun公司定义的一套操作所有关系型数据库的规则,即接口。
各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
下载
点击直接下载5.1.40
下载截图:
二、详细步骤
环境准备
在mysql中创建一个db3的数据库,并创建一个user表插入几条用户信息的数据
-- 创建一个编码为utf8 的数据库db3
create database db3 character set utf8;
use db3;
-- 创建user表
create table user (
id int primary key auto_increment,
name varchar(32), -- 用户名
password varchar(32) -- 密码
);
-- 添加一条数据
insert into user ( name, password ) values ( 'zhangsan', 123456 );
工程导入驱动jar包
- 1、下载之后解压
- 2、复制mysql的驱动包mysql-connector-java-5.1.40-bin.jar到工程上新建的lib目录下
- 3、右键.jar文件,选择add As Library 添加成库
1、加载数据库驱动
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
2、建立连接
String url = "jdbc:mysql://localhost:3306/db3";
String userName = "root";
String password = "root";
//获取与数据库的链接
Connection conn = DriverManager.getConnection(url, userName, password);
注意:如果是localhost:3306, mysql可以简写为jdbc:mysql:///db3
- connection 对象常用方法:
方法 | 描述 |
---|---|
createStatement() | 创建可执行sql的statement对象(容易产生sql注入问题) |
prepareStatement(sql) | sql参数使用?作占位符,返回一个预编译后的prepareStatement对象(解决了sql注入问题) |
setAutoCommit(boolean autoCommit) | 设置事务是否自动提交:在执行sql之前开启事务 |
commit() | 提交事务:当所有sql都执行完提交事务 |
rollback() | 回滚事务:在catch中回滚事务 |
3、执行SQL语句
- Statement 对象常用方法:
方法 | 描述 |
---|---|
boolean execute(String sql) | 可执行任意的sql语句,返回布尔值(一般不用) |
int executeUpdate(String sql) | 执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句,返回影响的行数(常用) |
ResultSet executeQuery(String sql) | 执行DQL(select)语句,返回一个ResultSet对象(常用) |
//使用statement 如:添加一条用户数据
//1、定义sql语句
String sql = "insert into user ( name, password ) values ( 'lisi', 1234 )";
//2、获取执行sql语句的对象
Statement st = conn.createStatement();
//3、定义sql语句并执行 如果count>0 则表示添加成功,否则添加失败
int count = st.executeUpdate(sql);
//推荐使用prepareStatement,如:查询登录用户是否匹配
//1、定义sql语句
String sql = "select * from user where name=? and password=?";
//2、获取执行sql语句的对象,需要传入sql,进行预编译
PrepareStatement pst = conn.prepareStatement(sql);
//3、设置值setXxx, Xxx代表获取字段的类型,如:setInt、setString
pst.setString(1, "lisi");
pst.setString(2, "1234");
//4、执行sql,不需要传递sql,直接返回结果对象
ResultSet rs = pst.executeQuery();
if(rs.next()){
//登录成功
}
4、获取查询的结果集
- ResultSet常用方法
//1、获取行,返回末尾是否有数据, 有则返回false,没有返回true
boolean next() //游标向下移动一行
//2.获取数据 Xxx 代表数据类型。 如:getInt(1) getString("name")
//根据列的编号获取值 从1开始
getXxx(int index);
//根据列的名称获取值
getXxx(String columName);
5、释放资源
1、需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接。
2、释放原则:先开的后关,后开的先关。ResultSet --> Statement --> Connection。
3、在finally中执行。
ResultSet rs = null;
Statement st = null;
Connection conn = null;
try{
//JDBC操作数据库代码实现
}catch{
//异常处理
}finally{
if(rs != null){
try {
rs.close();
} catch (SQLException throwables){
throwables.printStackTrace();
}
}
if(stm != null){
try {
stm.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
三、JDBC实现工具类 jdbcUtils
1、在src问件下创建一个jdbc.properties文件,用于修改配置文件,而不用修改代码
加上?characterEncoding=utf8 可以解决中文乱码问题
url=jdbc:mysql://localhost:3306/db3?characterEncoding=utf8
username=root
password=root
driver=com.mysql.jdbc.Driver
2、创建一个utils包,在包下创建一个JdbcUtils类
主要实现的方法:
- 1、得到数据库的连接对象 getConnection()
- 使用配置文件代替传递的参数
- 2、关闭所有打开的资源
- close(PreparedStatement pst, Connection conn)、
- close(ResultSet rs, PreparedStatement pst, Connection conn)
package com.yj.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String url = null;
private static String username = null;
private static String password = null;
private static String driver = null;
//文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
static {
try {
//1、创建properties集合类
Properties pro = new Properties();
//2、获取src路径下的jdbc.properties文件的方式--->ClassLoader 类加载器
InputStream rs = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//3、加载文件
pro.load(rs);
//4、获取值并赋值
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//5、注册驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
// 得到数据库连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//关闭所有打开的资源
public static void close(PreparedStatement pst, Connection conn){
if(pst != null){
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet rs, PreparedStatement pst, Connection conn){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(pst != null){
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3、使用工具类对db3数据库进行CRUD
package com.yj.jdbc;
import com.yj.utils.JdbcUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo02 {
//向数据库新增一条用户数据
@Test
public void insert(){
Connection conn = null;
PreparedStatement pst = null;
try {
conn = JdbcUtils.getConnection();
String sql = "insert into user (name, password) values (?, ?)";
pst = conn.prepareStatement(sql);
pst.setString(1,"王五");
pst.setString(2,"123");
int count = pst.executeUpdate();
if(count > 0){
System.out.println("添加成功");
}else{
System.out.println("添加失败");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(pst, conn);
}
}
//修改数据 (修改id=2这条数据的密码为123456)
@Test
public void update (){
Connection conn = null;
PreparedStatement pst = null;
try {
conn = JdbcUtils.getConnection();
String sql = "update user set password = ? where id = 2";
pst = conn.prepareStatement(sql);
pst.setString(1,"123456");
int count = pst.executeUpdate();
if(count > 0){
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(pst, conn);
}
}
//删除数据 (删掉id=2这条数据)
@Test
public void delete(){
Connection conn = null;
PreparedStatement pst = null;
try {
conn = JdbcUtils.getConnection();
String sql = "delete from user where id = 2";
pst = conn.prepareStatement(sql);
int count = pst.executeUpdate();
if(count > 0){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(pst, conn);
}
}
//查询 (查询id=1这条数据并打印所有字段)
@Test
public void retrieve(){
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from user where id = ?";
pst = conn.prepareStatement(sql);
pst.setInt(1,1);
rs = pst.executeQuery();
if(rs.next()){
System.out.println("id=" + rs.getInt("id"));
System.out.println("name=" + rs.getString("name"));
System.out.println("password=" + rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs, pst, conn);
}
}
}
四、使用数据库连接池
概念
其实就是一个容器(集合),存放数据库连接的容器。
好处
- 1、节约资源。
- 2、用户访问高效。
如何实现
- 1、接口:DataSource 下:
- 获取连接:getConnection()
- 归还连接:close()
- 2、一般我们不去实现它,由数据库厂商来实现,常用的有:
- C3P0: 数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供的
- 点击直接下载C3P0-0.9.5.2 和 Druid-1.0.9 jar包
1、C3P0的使用
- 1、导入jar包(两个)c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar,不要忘记导入数据库驱动的jar包
- 2、定义配置文件
- 名称:c3p0.properties 或者 c3p0-config.xml
- 位置:src文件目录下
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db3?characterEncoding=utf8</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<!--初始化申请的连接数量-->
<property name="initialPoolSize">5</property>
<!--最大的连接数量-->
<property name="maxPoolSize">10</property>
<!--超时时间-->
<property name="checkoutTimeout">3000</property>
</default-config>
<!-- 使用name参数读取连接池对象 -->
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db3?characterEncoding=utf8</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、创建数据库连接对象:comboPooleDataSource
//ComboPooledDataSource(String name)传入参数代表上面带有name属性的配置
//不传为默认
DataSource ds = new ComboPooledDataSource();
- 4、获取连接
Connection conn = ds.getConnection();
2、Druid的使用
-
1、导入jar包 druid-1.0.9.jar
-
2、定义配置文件,properties形式,任意名称,任意目录
如:druid.properties
url=jdbc:mysql://localhost:3306/db3?characterEncoding=utf8
username=root
password=root
driver=com.mysql.jdbc.Driver
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
- 3、加载配置文件
Properties pro = new Properties();
InputStrean is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
- 4、获取数据库连接池对象:DruidDataSourceFactory
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
- 5、获取连接
Connection conn = ds.getConnection();
- 6、也可以定义工具类来提高代码的复用性:只要实现获取连接,归还连接
五、Spring JDBC
提供了一个JDBCTemplate对象简化JDBC的开发
1、使用步骤
- 1、导入jar包(5个)
- 2、创建JdbcTemplate对象。依赖于数据源DataSource
//ds为数据库连接对象
JdbcTemplate template = new JdbcTemplate(ds);
- 3、调用JdbcTemplate的方法来完成CRUD的操作,不需要调用close方法
方法 | 描述 |
---|---|
update() | 执行DML语句。增、删、改语句 |
queryForMap() | 将查询1条结果集封装为map集合,将列名作为key,将值作为value |
queryForList() | 查询结果将结果集封装为list集合(注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中) |
query() | 查询结果,将结果封装为JavaBean对象(参数RowMapper,一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装) |
queryForObject() | 将结果封装为对象,一般用于聚合函数的查询 |
2、代码实现一个简单的例子
准备表的数据
-- 删除表的内容
truncate table user;
-- 添加一些数据
insert into user values (null, "张三", "abcd"), (null, "李四", "bbb"), (null, "王五", "ccc");
代码实现例子
-
- 修改1号数据的 password 为 aaa
-
- 添加一条记录
-
- 删除刚才添加的记录
-
- 查询id为1的记录,将其封装为Map集合
-
- 查询所有记录,将其封装为List
-
- 查询所有记录,将其封装为Emp对象的List集合
-
- 查询总记录数
public class Demo04 {
//使用c3p0来创建数据库连接对象
private JdbcTemplate template = new JdbcTemplate(new ComboPooledDataSource());
//1. 修改1号数据的 password 为 aaa
@Test
public void test1(){
String sql = "update user set password = 'aaa' where id = 1";
int count = template.update(sql);
if(count>0){
System.out.println("修改成功");
}
}
//2. 添加一条记录
@Test
public void test2(){
String sql = "insert into user values (null, ?, ?)";
int count = template.update(sql, "小明", "ddd");
if(count>0){
System.out.println("添加成功");
}
}
// 3. 删除刚才添加的记录
@Test
public void test3(){
String sql = "delete from user where id = ?";
int count = template.update(sql, 4);
if(count>0){
System.out.println("删除成功");
}
}
// 4. 查询id为1的记录,将其封装为Map集合
@Test
public void test4(){
String sql = "select * from user where id = 1";
Map<String, Object> map = template.queryForMap(sql);
System.out.println(map); //{id=1, name=张三, password=aaa}
}
// 5. 查询所有记录,将其封装为List
@Test
public void test5(){
String sql = "select * from user";
List<Map<String, Object>> list = template.queryForList(sql);
System.out.println(list);
//[{id=1, name=张三, password=aaa}, {id=2, name=李四, password=bbb}, {id=3, name=王五, password=ccc}]
}
// 6. 查询所有记录,将其封装为Emp对象的List集合
@Test
public void test6(){
String sql = "select * from user";
List<User> list = template.query(sql, new BeanPropertyRowMapper<User>(User.class));
System.out.println(list);
//[User{id=1, name='张三', password='aaa'}, User{id=2, name='李四', password='bbb'}, User{id=3, name='王五', password='ccc'}]
}
// 7. 查询总记录数
@Test
public void test7(){
String sql = "select count(id) from user";
Long total = template.queryForObject(sql, Long.class);
System.out.println(total); //3
}
}