JDBC API 是一系列的接口,统一和规范了应用程序与数据库链接,执行sql语句,并得到返回结果等。在java.sql 和 javax.sql 中
1. JDBC概述和原理
** 1. 概述**
** (1)JDBC为Java程序操作不同的数据库提供了统一的接口,避免了细节.**
** (2)JDBC可以链接任何提供了JDBC的驱动程序的数据库系统,从而完成对数据库的任何操作.**
** 2. 原理示意图**
2. JDBC快速入门
** 1. JDBC程序有四个步骤**
** (1) 加载驱动 -- 加载Driver 类**
** (2) 获取连接 -- connection**
** (3)写sql语句 -- CRUD**
** (4) 释放资源-- close**
** 2. 第一个JDBC程序**
先在数据库 db_02 中,建一个actor表
create table Person (idt primary key inauto_increment,
name
varchar(32),sex varchar(1),phone varchar(12));
** (1)在加载驱动之前,先要导入 jar 包,其中含有 MySQL厂商 实现java提供接口的规范的类.**
** 1. 下载jar包,前往 mysql官网**
** 2. 在java项目下建一个目录 把 jar 文件复制到该目录中**
** **
** 3. 导入项目 右键jar 选择 add...**
![](https://img-blog.csdnimg.cn/2fc8b39b874c4f9a9834913af735436c.png)
** 1. 加载驱动**
** 2. 获得连接**
** 3. 写sql语句**
** 4. 释放资源**
三. 数据库连接的五种方式
** 1. 就是通过 Driver ,不过是静态加载,依赖性很强**
//加载驱动
Driver driver = new Driver();
// 2. 获得连接
// jdbc:mysql:// 固定,是协议
// localhost:3306/ IP 地址 和 端口号
// db_02 数据库
String url = "jdbc:mysql://localhost:3306/db_02";
// 把用户和密码 封装到集合 properties 中
Properties properties = new Properties();
properties.setProperty("user", "root");
properties.setProperty("password","liubo321");
//获得连接
Connection connect = driver.connect(url, properties);
// 3. 编写sql语句 (1) 首先写sql语句(2)获得statement对象写入
String sql = "insert actor values(null , '蔡徐坤', '男', '146843489')";
Statement statement = connect.createStatement();
int i = statement.executeUpdate(sql); // 该对象可以写静态sql语句,并返回结果的行数 大于 0 即为成功
System.out.println(i > 0 ? "成功" : "失败");
//4. 释放资源
connect.close();
statement.close();
2. 通过反射,动态加载 Driver,依赖性降低
public void connect02 () throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) aClass.newInstance();
}
3. 使用 DriverManager 统一管理
**4. 利用反射机制,自动注册驱动 **
public static void connect04 () throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/db_02";
String user = "root";
String password = "liubo321";
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
5. 通过配置文件,更加灵活读取
public static void connect05 () throws IOException, ClassNotFoundException, SQLException {
Properties properties = new Properties();
properties.load(new FileInputStream("src//mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url,user,password);
System.out.println(connection);
}
配置文件 mysql.properties
四、ResultSet
** 1. 概述**
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
Properties properties = new Properties();
properties.load(new FileInputStream("src//mysql.properties"));
String driver = properties.getProperty("driver");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
String sql = "select * from actor";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = resultSet.getInt(1);//获取第一行信息
String name = resultSet.getString(2);//获取第二行信息
String sex = resultSet.getString(3);//获取第三行信息
String phone = resultSet.getString(4);//获取第四行信息
System.out.println(id + "\t" + name + "\t" + sex + "\t" + phone);
}
connection.close();
statement.close();
}
五、SQL注入
** 一、Statement 存在的危险**
** 1. Statement 对象 用于执行静态SQL语句并返回其生成的结果**
** 2. 在建立连接之后,需要对数据库进行访问,执行命名或是sql语句,可以通过 **
Statement [存在SQL注入问题]
**PreparedStatement【预处理】**
** CallableStatement 【存储过程】**
**3. SQL注入,是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法SQL语句段或者命令,恶意攻击数据库.**
二、使用 PreparedStatement 解决
** 1. 免去拼接字符串**
** 2. 有效解决SQL注入问题**
** 3.减少编译次数,提高效率**
使用 PreparenStatement 对象 ,
select * from emp where ename = ?and id = ?;
** 1. ? 代表占位符,可以使用 PreparenStatement 对象 提供一系列的setXXX ()方法,第一个参数代表第几个问号 从1开始**
2. executeQuery 返回结果集
3. executeUpdate (增,删,该)语句,返回 int 值,代表受影响的行数,大于0 成功
** 案例:使用PerparenStatement 完成对 表 actor 查询**
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
// 加载驱动
String driver1 = properties.getProperty("driver");
Class.forName(driver1);
// 2. 连接,向配置文件读取信息
properties.load(new FileInputStream("src//mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
// 创建连接
Connection connection = DriverManager.getConnection(url, user, password);
String sql = "select * from actor where id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,2);//查询ID为2的信息
ResultSet resultSet = preparedStatement.executeQuery();
System.out.println(resultSet.next() ? "成功" : "失败");
}
六、JDBC API梳理
1. DriverManager
1. getConnection(url,user,password) 获得链接
2.Statement 接口(存在SQL注入问题)
1. executeUpdate(sql)执行dml语句
2.executeQuery(sql) 执行select语句,返回结果集
3. execute (sql) 执行任意语句,返回boolean值
** 3. PreparedStatement 接口(预处理)**
1. executeUpdate(sql)执行dml语句
2.executeQuery(sql) 执行select语句,返回结果集
3. execute (sql) 执行任意语句,返回boolean值
4.setXXX(占位符索引,赋予占位符的值),解决SQL注入
5. setObject(占位符索引,赋予占位符的值)
4. ResultSet(结果集)
1. next()向下移动,同时没有行返回false
2. previous() 向上移动,如果没有上一行返回false
3.getXXX(列的索引 | | 列的名称),获得对应列的值,接受类型是XXX
4.getObject (列的索引 | | 列的名称)获得对应列的值,接受类型是Object
七、事务
** 1. jdbc 事务概述**
·基本介绍
1.JDBC程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
2.JDBC程序中为了让多个SQL语句作为一个整体执行,需要使用事务
3.调用Connection 的 setAutoCommit(false) 可以取消自动提交事务
4.在所有的SQL语句都成功执行后,调用commitO;方法提交事务
5.在其中某个操作失败或出现异常时,调用rollback0;方法回滚事务
** 2.批处理 **
简述
1.当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句 一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。 2.JDBC的批量处理语句包括下面方法: **addBatch(O:添加需要批量处理的SQL语句或参数 executeBatch():执行批量处理语句; clearBatch():清空批处理包的语句** 3.JDBC连接MySQL时,如果要使用批处理功能,请再url中加参
数 ?rewriteBatchedStatements=true
4.批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减
少运行次数,效率大大提高
八、数据库连接池 内含 C3P0 and Druid 下载地址
** 1. 传统链接弊端 **
** 1. 对于每次建立一次链接,就要从Connection 对象 ,验证IP,密码等**
** 2. 不能控制连接数量,如果数量过多会导致MySQL奔溃**
** 3. 对于每一次连接,都要关闭,如果程序出现问题,会导致内存泄漏,导致重启MySQL**
** 2. 数据库连接池基本原理**
** 3. 连接池的种类**
数据库连接池种类
1.JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource 只是一个接口,该接口通常由第三方提供实现
2.C3P0 数据库连接池,速度相对较慢,稳定性不错(hibernate,spring)
3.DBCP数据库连接池,速度相对c3p0较快,但不稳定
4.Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
5.BoneCP数据库连接池,速度快
6.Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3PO、Proxool
优点于一身的数据库连接池
4. C3P0 连接方式
** 1. 导入jar包 下载官网 C3P0 jar包下载地址**
@Test
//C3P0 第一种连接方式 ,用户密码,driver url 在程序中方设定
public void C3p01 () throws IOException, PropertyVetoException, SQLException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
Properties properties = new Properties();
properties.load(new FileInputStream("src//mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
// 2 配置连接数据库的信息
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setDriverClass(driver);
// 初始化
comboPooledDataSource.setInitialPoolSize(10);//初始化连接数
comboPooledDataSource.setMaxPoolSize(50);//设置最大连接数
// 3 获得链接
Connection connection = comboPooledDataSource.getConnection();
System.out.println("连接成功");
connection.close();
2. 通过配置文件 来完成对数据库连接所需的信息
** 1. 在src目录下 建 c3p0-config.xml 文件**,其内容如下
<c3p0-config> <!--使用默认的配置读取数据库连接池对象 --> <named-config name="小鲨鱼"> <!--加载驱动的Driver路径--> <property name="driverClass">com.mysql.jdbc.Driver</property> <!--指定连接数据库--> <property name="jdbcUrl">jdbc:mysql://localhost:3306/db_02</property> <!--连接数据库的用户--> <property name="user">root</property> <!--对应的密码--> <property name="password">123456</property> <!-- 连接池参数 --> <!--初始化申请的连接数量--> <property name="initialPoolSize">5</property> <!--每次增长链接的数--> <property name="acquireIncrement">5</property> <!--最大的连接数量--> <property name="maxPoolSize">10</property> <!--最小连接数--> <property name="minPoolSize">5</property> <!--超时时间--> <property name="checkoutTimeout">3000</property> <!--每个连接对象可连接的最多的命令对象数--> <property name="maxStatementsPerConnection">2</property> </named-config> </c3p0-config>
** 2. 通过程序向连接池中取出连接**
public void C3P02 () throws SQLException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("小鲨鱼");
Connection connection = comboPooledDataSource.getConnection();
System.out.println("通过配置文件连接");
}
5. 德鲁伊连接池 德鲁伊JAR包下载地址
** 步骤**
** 1. 从官方下载 druid jar 包,导入项目中 **
** 2. 在src下面加入 druid 的配置文件**
** 3. 加载驱动,使用 ** DruidDataSourceFactory.createDataSource(properties);
** 4. 获得连接**
** 1. 案例:对MySQL数据库完成连接使用Druid连接池**
public class Druid_ {
@Test
public void Druid_connection_pool() throws Exception {
// 创建properties对象,加载信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\Druid-config.properties"));
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
dataSource.getConnection();
System.out.println("连接成功");
}
** 2. 配置 Druid-config.perproties 配置文件如下 导入 src 目录下**
#key=vlaue
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_02?rewriteBatchedStatements=true
username=root
password=liubo321
initialSize=10
maxActive=50
maxWait=5000
六、Apche-DButils
** 简述**
** 由于,上述方法,Connection 释放资源时,返回的ResultSet就不能使用。要对ResultSet数据可以想使用的时候就使用,我们要把这个结果集,封装到ArraryList<类>中,该类的属性与表中字段相等,该类称为JavaBean**
JavaBean 是为该类是表的映射
代码实现 - Actor 类
package com.study.myDButils;
/**
* +----+-----------+------+------+-----------+
* | id int name varchar | sex varchar | sorc double | phone varchar |
* +----+-----------+------+------+-----------+
* actor 表
*/
public class Actor {
private Integer id;
private String name;
private String sex;
public Double sorc;
public String phone;
public Actor() {//必须提供无参构造器
}
public Actor(Integer id, String name, String sex, Double sorc, String phone) {
this.id = id;
this.name = name;
this.sex = sex;
this.sorc = sorc;
this.phone = phone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Double getSorc() {
return sorc;
}
public void setSorc(Double sorc) {
this.sorc = sorc;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Actor{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", sorc=" + sorc +
", phone='" + phone + '\'' +
'}';
}
}
** 结果集保存**
@Test
public void MyDButils01() throws SQLException {
ArrayList<Actor> actors = new ArrayList<>();//JavaBean 把结果集保存在ArrayList中
Connection connection = JdbcDruid.getConnection();//获得连接
String sql = "select * from actor where id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);//获取preparedStatement执行sql语句
preparedStatement.setInt(1,1);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
double sorc = resultSet.getDouble("sorc");
String phone = resultSet.getString("phone");
actors.add(new Actor(id,name,sex,sorc,phone));
}
JdbcDruid.close(preparedStatement,connection,resultSet);
System.out.println(actors);
}
对上述方法进行优化 - 引出 Apche-DButils
** 1. 对 **Apche-DButils 介绍 下载JAR包
·基本介绍
- commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的封装,
使用dbutils能极大简化jdbc编码的工作量· DbUtils类
1.QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理
2.使用QueryRunner类实现查询
3.ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形
式,
Q
1.ArrayHandler:把结果集中的第一行数据转成对象数组。
2. ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
3. BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
4. BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
5. ColumnListHandler:将结果集中某一列的数据存放到List中。
6. KeyedHandler(name):将结果集中的每行数据都封装到Map里,再把这些map再存到一个map里,其key为指定的key。
7. MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
8. MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List9. ScalarHandler 返回一个字段一列信息
** 2. 案列:使用 DbUtils 完成对actor表的查询,并把结果集加到list中**
package com.study.myDButils;
import com.study.F_jdbc.untils.JdbcDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* 使用DbUtils 完成对actor表的查询,并把结果集加到list中
*/
public class DButils {
@Test
public void DButlis01() throws SQLException {
Connection connection = JdbcDruid.getConnection();
String sql = "select * from actor where id >= ?";
QueryRunner queryRunner = new QueryRunner();
/**
* connection 放入一个链接
* sql 写入sql语句
* new BeanListHandler<>(Actor.class)
* 通过反射 获得Actor的属性,并把结果集存在List中
* 最后为可变参数,是 给 ? 占位符 赋值
*/
List<Actor> query = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
for(Actor a :query) {
System.out.println(a);
}
//queryRunner.query 会自动吧statement 关闭,和 resultSet
JdbcDruid.close(null,connection,null);
}
}
** QueryRunner对象中.update 方法,执行失sql语句的DML语句、**
public void DButils_DML() throws SQLException {
Connection connection = JdbcDruid.getConnection();
String sql = "delete from actor where id = ?";
// int 返回的是sql语句影响表中的行数
int update = new QueryRunner().update(connection, sql, 1);
System.out.println(update > 0 ? "删除成功" : "没有影响到表");
}
}
十、BasicDAO
DAO - - - Data Access Object 【数据访问对象】
概述上述代码缺点
1. SQL 语句写死,不能通过参数传递,通用性不好. 2. 对于 select 语句 返回结果集,返回类型不确定.
** 2. 编写BasicDAO**
** 1. 建四个包,分别存入不同的类**
** 1. com.study.dao_**
** 2. com.study.dao_.JavaBean // 存放 与表中数据映射的类**
** 3. com.study.dao_.utils // 存放工具类**
** 4. com.study.dao_.dao //存放 XXxDAO**
** 5.com.study.dao_.text // 测试类**
** 1. com.study.dao_.dao **
package com.study.dao_.dao;
import com.study.dao_.utils.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* 完成其他DAO对象使用的方法
*/
public class BasicDao<T> {
private QueryRunner qr = new QueryRunner();
private Connection connection = null;
//执行dml语句
public int queryDate (String sql,Object...parameters) {
int updates;
try {
this.connection = JDBCUtilsByDruid.getConnection();
updates = qr.update(connection,sql,parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,connection,null);
}
return updates;
}
//查询多行结果集
public List<T> queryMulti (String sql, Class<T> aclass,Object... parameters) {
try {
this.connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection, sql, new BeanListHandler<>(aclass), parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,connection,null);
}
}
//查询单行数据
public T querySingle (String sql, Class<T> aclass, Object...parameters) {
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection,sql,new BeanHandler<>(aclass),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,connection,null);
}
}
//查询单行单列数据
public Object queryScalar (String sql, Object...parameters) {
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection,sql,new ScalarHandler<>(),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,connection,null);
}
}
}
** 2. com.study.dao_.domain**
package com.study.dao_.domain;
/**
* +----+-----------+------+------+-----------+
* | id int name varchar | sex varchar | sorc double | phone varchar |
* +----+-----------+------+------+-----------+
* actor 表
*/
public class Actor {
private Integer id;
private String name;
private String sex;
public Double sorc;
public String phone;
public Actor() {//必须提供无参构造器
}
public Actor(Integer id, String name, String sex, Double sorc, String phone) {
this.id = id;
this.name = name;
this.sex = sex;
this.sorc = sorc;
this.phone = phone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Double getSorc() {
return sorc;
}
public void setSorc(Double sorc) {
this.sorc = sorc;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Actor{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", sorc=" + sorc +
", phone='" + phone + '\'' +
'}';
}
}
- com.study.dao_.tex
package com.study.dao_.text;
import com.study.dao_.dao.ActorDao;
import com.study.dao_.domain.Actor;
import org.junit.jupiter.api.Test;
import java.util.List;
public class TextDao {
@Test
public void text01() {
ActorDao actorDao = new ActorDao();
String sql = "select * from actor where id > ?";
List<Actor> list = actorDao.queryMulti(sql, Actor.class,2);
for(Actor actor : list) {
System.out.println(actor);
}
//单行记录
String sql1 = "select * from actor where id = ?";
Object o = actorDao.querySingle(sql, Actor.class, 3);
System.out.println("单行记录");
System.out.println(o);
//单行单列信息
String sql3 = "select name from actor where id = ?";
Object o1 = actorDao.queryScalar(sql3, 3);
System.out.println("单列数据");
System.out.println(o1);
}
}
版权归原作者 一直在进步的派大星 所有, 如有侵权,请联系我们删除。