数据库之JDBC
1、简单认识一下JDBC
- 1)、JDBC是什么?
- java database connection java数据库连接
- 作用:就是为了java连接mysql数据库嘛
- 要详细的,就面向百度编程吧
- 2)、JDBC是一种驱动,那么它位于哪个地方?
- 3)、JDBC的实现 ———— 五步骤
- 加载驱动
- 获取连接 driverManager
- 获取执行sql的对象 statement / PreparedStatement
- 获取结果集 resultSet
- 释放资源
- 快速上手操作一下
- (1)、准备工作 —— 下载JDBC
- 下载网址:MySQL :: Download MySQL Connector/J (Archived Versions)
- 选择自己想要的版本( 我的是:5.1.34 )
- (1)、准备工作 —— 下载JDBC
- 快速上手操作一下
- 再来数据库创建一个数据库 和 表
CREATE DATABASE IF NOT EXISTS jdbc; USE jdbc; CREATE TABLE IF NOT EXISTS person(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(20) NOT NULL,
sex CHAR(2) NOT NULL,
age INT NOT NULL
)ENGINE = INNODB DEFAULT CHARSET = utf8; INSERT INTO person
VALUES( NULL , '紫邪情' , '女' , '18' ),
( NULL , '君莫邪' , '男' , '19' ),
( NULL , '张雪' , '女' , '19' ),
( NULL , '韩非' , '男' , '19' );
- 再来数据库创建一个数据库 和 表
- 然后把下载的JDBC弄到java项目中去
-
标记文件类型
-
标记成功之后jar包前面有一个 > 符号
-
-
- 然后把下载的JDBC弄到java项目中去
- (2)、利用五步骤。开始测试
package cn.xieGongZi.test; import java.sql.*; public class PlayJDBC { public static void main(String[] args) throws ClassNotFoundException, SQLException { // 1、加载驱动 利用了反射
Class.forName("com.mysql.jdbc.Driver"); // 这个是死的 这里为了看逻辑,所以把异常抛出 /*
* jdbc:mysql: 是指协议 这是固定写法
* localhost 是主机地址 这里使用127.0.0.1也可以,要是想连接别人电脑上的数据库,这里把ip地址换了就可以了
* 3306 指:sql的端口号
* jdbc 就是要链接的数据库
* ? 表示要跟参数 即:? 后面的就是参数
* characterEncoding 指:设置字符编码 其他的参数都可以少,这个最好别少
* useUnicode 使用Unicode编码格式
* useSSL 使用安全套接层协议 即:安全连接
*
* 因此:这个url的写法就出来了:
* 协议 : // 主机地址 : 端口号 / 数据库名 ? 参数
* */
String url = "jdbc:mysql://localhost:3306/jdbc? characterEncoding = utf-8 && useUnicode = true && useSSL = true";
String username = "root"; // 这是数据库的用户名
String password = "072413"; // 这是数据库的密码 要操作数据库肯定要登进去涩,所以:路径是什么?用户名和密码时什么肯定需要告知嘛 // 2、获取连接 使用DriverManager 这是java.sql包下的
Connection con = DriverManager.getConnection(url, username, password);
// 发现这个getConnection需要三个参数 url 、 username 、 password,所以建一下,需要处理异常,为了好看逻辑,照样跑出去 // 3、通过链接对象 去 获取执行sql的对象
Statement st = con.createStatement(); String sql = "select * from person"; // 在这个地方有些人可能会出现 表名 识别不了 那就用 库名.表名 如:jdbc.person
// 这里进行查询操作 注:在java中, 增删改 是executeUpdate( String sql )方法 查询是executeQuery( String sql )方法
// 4、执行sql,获取结果集
ResultSet rs = st.executeQuery(sql); // 发现这个方法需要一个sql , 那么编写一句 // sql语句弄好了,结果集resultSet也得到了,但是看名字就知道ResultSet肯定是一个容器嘛,所以得把结果拿出来涩
// 使用一个方法 next() 这是看下一行是否有数据 怎么理解呢?
// 就是去读写数据时,有一个指针,这个指针是指向数据库表的表头的,即:列字段哪一行 什么name、age、sex....这一行
// 所以:去一行一行读写时,是看下一行是否有数据
while ( rs.next() ){ // 当然:要是数据只有一行的话 用个if就可以了
System.out.print( rs.getInt("id") + " " );
System.out.print( rs.getString("name") + " " );
System.out.print( rs.getString("sex") + " " );
System.out.println( rs.getInt("age") + " " );
} // 5、释放资源 ———— 倒着关闭
if ( rs != null ){ // 在这里这个if不要都行,为了后续代码的健壮性,严谨,所以这里加了一个判断罢了
rs.close();
} if ( st != null ){
st.close();
} if ( con != null ){
con.close();
} }
}
- (2)、利用五步骤。开始测试
效果如下( 成功从数据库中拿到数据了 ):
- 对JDBC的总结和补充
- JDBC的步骤
- 加载驱动 Class.forName("com.mysql.jdbc.Driver");
- 获取连接 Connection con = DriverManager.getConnection( String url , String username , String password );
- 获取执行sql的对象 Statement st = con.CreateStatement();
- 获取结果集 / 获取受影响的行数( 这个是增删改的时候的结果 ) ResultSet rs = st.executeQuery( String sql ); 增删改就是executeUpdate( String sql )
- 释放资源 close()
- JDBC的步骤
- 对一些方法的补充:
- Connection中常用的方法
- 这就是一个连接对象嘛,它代表的就是数据库。所以它可以设置数据库中的任何东西
- rollback 回滚
- autocommit 自动提交
- commit 提交事务
- createStatement 创建执行sql的对象 —— 提前讲一下:这个对象不安全
- preparedStatement 这个也是创建执行sql的对象 ———— 这个更安全,后续会说明
- close 关闭连接
- 其他的方法 直接通过 Connection. 之后就可以看到它所有的方法了
- 这就是一个连接对象嘛,它代表的就是数据库。所以它可以设置数据库中的任何东西
- Connection中常用的方法
- 对一些方法的补充:
- Statement中常用方法
- executeQuery 执行sql查询语句 返回的是一个结果集 ResultSet
- executeUpdate 执行sql增 / 删 / 改 语句 返回的是受影响的行数
- execute 执行任何的sql语句
- close 关闭资源
- Statement中常用方法
- ResultSet中常用方法
- getObject 在不知道数据库中字段的类型时采用,获取任意类型嘛
- 获取对应类型
- getString
- getInt
- getDouble
- ........
- 移动指针
- beforeFirst 移动到最前面 即:表头的位置
- afterLast 移动到最后面 即:数据的最后一行
- next 移动到下一行数据
- previous 移动到前一行数据
- absolute( int row ) 移动到指定行
- 关闭资源
- close
- ResultSet中常用方法
- 4)、JDBC的封装
- 为什么需要封装?
- 前面那个JDBC五步骤是固定的,那么每有一个类需要进行操作数据库时不得都要写一次吗,那里面有很多共同的代码,只有个别不同而已,所以:不就可以提取成一个工具类吗
- 为什么需要封装?
- (1)、自己进行的封装
- ①、简单封装
- 加入实体类 —— 即:sql中的一张表对应java中的一个实体类 实体类的包名为 pojo / vo / entity 都可以
- 加入实体类 —— 即:sql中的一张表对应java中的一个实体类 实体类的包名为 pojo / vo / entity 都可以
- ①、简单封装
- (1)、自己进行的封装
package cn.xieGongZi.pojo; // 加入对应数据库中的列字段 成为 属性
// 加入get 和 set 方法
// 加入toString方法 public class Person { private int id;
private String name;
private String sex;
private int age; @Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
} public Person() {
} public Person(int id, String name, String sex, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
} public int getId() {
return id;
} public void setId(int 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 int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} }实体类完毕!
- 封装JDBC
- 建一个utils包
- 建一个utils包
- 封装JDBC
- 开始封装JDBC
package cn.xieGongZi.utils; import java.sql.*; public class JDBCUtils { private static String url;
private static String username;
private static String password; static { try {
// 加载驱动
Class.forName("com.mysql.jdbc.Driver"); // 编写url、username、password
url = "jdbc:mysql://localhost:3306/jdbc?characterEncoding = utf-8 && useUnicode = true && useSSL = true ";
username = "root";
password = "072413";
} catch (ClassNotFoundException e) {
e.printStackTrace();
} } // 1、设置获取链接方法
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection( url , username , password );
} // 2、封装释放资源方法
public static void release(Connection con , Statement st , ResultSet rs ){
if ( rs != null ){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( st != null ){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( con != null ){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} // 3、在这里 再把增删改 和 查询方法封装起来也行 目前不演示了
}
- 开始封装JDBC
- 通过加入实体类,测试封装的JDBC
- 编写数据操作层
package cn.xieGongZi.dao; import cn.xieGongZi.pojo.Person;
import cn.xieGongZi.utils.JDBCUtils; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List; public class PersonDao { public List<Person> getAllPerson(){ // 创建一个集合 用来装查询的结果 从情况来看:ArrayList集合更适合 因为:有可能查出来的数据有重复的、而且最好有序
ArrayList<Person> list = new ArrayList<>(); // 1、加载驱动、获取链接已经在工具类中封装了 所以:直接拿来用
Connection con = null; // 提示作用域 因为:放在try里面的话,在后面释放资源哪里拿不到这三个参数
Statement st = null;
ResultSet rs = null;
try {
con = JDBCUtils.getConnection(); // 2、获取操作执行sql的对象
st = con.createStatement(); // 编写sql语句
String sql = "select id , `name` , sex , age from person"; // 3、执行sql语句 , 获得结果集
rs = st.executeQuery(sql); // 加入了实体类 所以:需要把结果集中的数据 弄到 实体类中去
// 所以:还得有个实体类诶
Person people = new Person();
while ( rs.next() ){ // 遍历结果集 准备把数据 放到 实体类中
people.setId( rs.getInt("id") );
people.setName( rs.getString("name") );
people.setSex( rs.getString("sex") );
people.setAge( rs.getInt("age") ); // 最后:把people 装到 list集合中去 一开始玩这一步不要都行
// 只是:这里是为了给后面的三层架构打基础
list.add( people );
} } catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.release( con , st , rs ); // 释放资源 有null的,在JDBCUtils中会自行判断
} return list; // 这里返回,然后在其他地方也就可以拿到这个结果了
}
}
- 编写数据操作层
- 通过加入实体类,测试封装的JDBC
- 测试一下:
- 测试一下:
- ②、上面的封装还是麻烦,不太满意,那就再来封装
- 一样的,先建好对应的包 写好对应的东西:实体类 当然:不用我这么建也可以,根据自己想法来
- 一样的,先建好对应的包 写好对应的东西:实体类 当然:不用我这么建也可以,根据自己想法来
- ②、上面的封装还是麻烦,不太满意,那就再来封装
- 在玩javaSE的集合时,不是弄过一个hashtable的儿子 —— Properties吗,来用一下它
- 在玩javaSE的集合时,不是弄过一个hashtable的儿子 —— Properties吗,来用一下它
- 继续封装JDBC
package cn.xieGongZi.utils; import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties; public class JDBCUtil { // 把driver、url、username、password放到了properties中了,那么就加载出来
private static String driver;
private static String url;
private static String username;
private static String password; static {
// 通过类加载器加载出db.properties —— 输入流嘛
InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/db.properties"); // 创建一个properties对象
Properties ppt = new Properties(); // 把流管道中的东西加载到properties中来
try {
ppt.load(in); // 把装到properties中的东西 获取出来
driver = ppt.getProperty("driver");
url = ppt.getProperty("url");
username = ppt.getProperty("username");
password = ppt.getProperty("password"); // 顺便做一件事情:加载驱动
Class.forName( driver );
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
} // 1、封装获取数据库链接对象的方法 这样别人只需要用我提供的其他方法即可
private static Connection getConnection() throws SQLException {
return DriverManager.getConnection( url , username , password );
} // 2、提供释放资源的方法
public static void release(Connection con , Statement st , ResultSet rs ){
if ( rs != null ){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( st != null ){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( con != null ){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} // 3、把增删改的方法也封装了
public static int update( String sql ) throws SQLException { // 原生的JDBC在增删改语句执行之前做了什么? // 1、加载驱动 —— 前面已经做了 // 2、获取数据库链接对象 —— 前面封装了 所以直接拿来用
Connection con = getConnection();// 异常抛出去 // 3、通过数据库链接对象 获取 执行sql的对象
Statement st = con.createStatement(); // 4、执行sql 得到受影响的行数
int rowCounts = st.executeUpdate(sql); return rowCounts; // 这里可以一步到位:return st.executeUpdate( sql ) ;
} // 4、继续封装 把查询方法也封装了
public static ResultSet query( String sql ) throws SQLException { // 前面都是一样的涩 复制过来
// 原生的JDBC在增删改语句执行之前做了什么? // 1、加载驱动 —— 前面已经做了 // 2、获取数据库链接对象 —— 前面封装了 所以直接拿来用
Connection con = getConnection();// 异常抛出去 // 3、通过数据库链接对象 获取 执行sql的对象
Statement st = con.createStatement(); // 4、执行sql 返回结果集
return st.executeQuery(sql); } }
- 继续封装JDBC
- 封装好了,那来测试一下
- 编写数据操作层 即:dao层
package cn.xieGongZi.dao; import cn.xieGongZi.pojo.Person;
import cn.xieGongZi.utils.JDBCUtil; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List; public class Persondao { public List<Person> getAllPerson() { ArrayList<Person> list = new ArrayList<>(); // 原生JDBC前面做了什么? // 1、加载驱动 —— 在JDBC工具类中已经封装了 // 2、获取数据库链接对象 ———— 还是在JDBC中封装了 这里可用可不用 —— 看封装增删查改方法的过程
// 我在增删查改中是直接调用了 getConnection() 不是当参数传进去了,所以:这里直接不用调,因为:增删改查中调用了 // 编写sql语句
String sql = " select id , `name` , sex , age from person";
// 3、获取执行sql的对象 返回结果集 —— 封装了 直接调用
ResultSet rs = null;
Statement st = null;
Connection con = null;
try {
rs = JDBCUtil.query(sql); // 拿到结果集了 那么把结果集中的数据放到list集合中
// 还是需要一个Person实体类对象
Person person = new Person();
while ( rs.next() ){
person.setId( rs.getInt("id") );
person.setName( rs.getString("name") );
person.setSex( rs.getString("sex") );
person.setAge( rs.getInt("age") ); // 把person放到list中 这样就可以在其他地方也拿到了
list.add( person );
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 最后释放资源
JDBCUtil.release( con , st , rs ); // 发现这里拿不到ResultSet 那么提升作用域
// 发现需要Connection 、 Statement对象,那就创建一下,让它等于null 这样在JDBCUtil中会自行判断
} return list;
}
}- 效果如下:
- 编写数据操作层 即:dao层
- 封装好了,那来测试一下
- 最后:这你妹嘞个巴子滴,和前面的封装不是一样的吗?
- 不一样,这种是建议用的一种( 是抛开后面用的连接池啊 ),因为这种速度更快一点,以及分工更明确一点( 更像编程思维嘛 )
- 最后:这你妹嘞个巴子滴,和前面的封装不是一样的吗?
- ③、前面都是用的Statement这个执行sql的对象,但是:一开始我便提过一点 这个对象不安全,因为:它不能防止SQL注入
- SQL注入是什么意思?
- 简单理解就是:这是SQL的一个漏洞,别人在攻击数据库时,可以通过逻辑正确,但非法的方式进入到数据库中,从而导致:数据泄露
- SQL注入是什么意思?
- ③、前面都是用的Statement这个执行sql的对象,但是:一开始我便提过一点 这个对象不安全,因为:它不能防止SQL注入
- 来体验一下
- 一样的,把对应的包创建好
- 一样的,把对应的包创建好
- 来体验一下
- 简单模仿一下登录业务流程
- 建一下表、并插入数据
CREATE TABLE IF NOT EXISTS `user`(
username VARCHAR(20) NOT NULL,
`password` VARCHAR(10) NOT NULL
)ENGINE = INNODB DEFAULT CHARSET = utf8; INSERT INTO `user` VALUES( '紫邪情' , '072413' ),
( '君莫邪' , '123456' ),
( '韩非' , '774931' )
- 建一下表、并插入数据
- 简单模仿一下登录业务流程
package cn.xieGongZi.test; import cn.xieGongZi.utils.JDBCUtil; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; public class Demo { public static void login( String username , String password ){ // 编写sql
String sql = " select * from `user` where username = ' "+username+" ' and password = ' "+password+" ' ";
// 因为转义字符的关系 所以:这里的' "+usernmae+" ' 在外面加了一个 `` 飘字符 // 执行sql 获得结果集
Connection con = null; // 提升作用域
Statement st = null;
ResultSet rs = null;
try {
rs = JDBCUtil.query(sql); while ( rs.next() ){ System.out.println( rs.getString("username") );
System.out.println( rs.getString("password") );
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.release( con , st , rs );
}
} // 测试一下
public static void main(String[] args) { // 模仿一下登录业务流程
// 前面第二种封装就是使用的Statement对象
login( " 'or' 1=1 " , " 'or' 1=1 "); // 这里使用逻辑正确,但是:违法的技巧
}
}
- 效果如下:
- 成功达到目的,因此:Statement不建议使用,不安全,最好使用我接下来要说明的这个对象 PreparedStatement。
- 当然:要是有人整 —— 我前面用的db.properties中有数据库用户名 和 密码,所以可以做到,那就别扯了,这是两码事儿。
- 因此:要是有人说用statement这个执行sql语句的对象的话,那他就是个草包,听都别听他鬼扯。
- 效果如下:
- PreparedStatement对象 —— 预编译对象
- 前面的流程都一样 使用 添加实体类 、 db.properties 所以不演示了,主要从封装JDBC开始,把Statement对象换了
- PreparedStatement对象 —— 预编译对象
- JDBC的封装
package cn.xieGongZi.utils; import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties; public class JDBCUtil { private static String driver;
private static String url;
private static String username;
private static String password; static { InputStream ins = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/db.properties"); Properties ppt = new Properties();
try {
ppt.load( ins ); driver = ppt.getProperty("driver");
url = ppt.getProperty("url");
username = ppt.getProperty("username");
password = ppt.getProperty("password"); Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
} // 封装获取数据库链接对象
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
} // 提供释放资源的方法
public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象 if ( rs != null ){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( ps != null ){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( con != null ){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} }
- 数据操作层
package cn.xieGongZi.dao; import cn.xieGongZi.pojo.Person;
import cn.xieGongZi.utils.JDBCUtil; 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 PersonDao { public List<Person> getAllPerson() { ArrayList<Person> list = new ArrayList<>(); // 提升作用域
Connection con = null;
PreparedStatement ps = null; // 使用preparedStatement对象
ResultSet rs = null; // 还是一样 获取链接
try {
con = JDBCUtil.getConnection(); // 编写sql语句
// 因为:使用的是preparedStatement对象,所以这里有点区别
String sql = " select * from person where `name` = ? "; // 使用占位符 ? 来代替要赋的值 在后面再给它赋值 // 执行sql
ps = con.prepareStatement(sql);
// 对占位符进行赋值
ps.setString(1,"紫邪情"); // 这表示给第一个参数( 即:? ),有多个的话,数值依次往后,跟着赋值即可 // 现在再开始执行sql 得到结果集
rs = ps.executeQuery(); Person people = new Person(); while ( rs.next() ){
people.setId( rs.getInt("id"));
people.setName( rs.getString("name"));
people.setSex( rs.getString("sex"));
people.setAge( rs.getInt("age")); list.add( people );
} } catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.release( rs , ps , con );
} return list;
}
}效果如下:
- (2)、使用别人封装好的 ———— 连接池
- ①、什么是连接池?
- 在javaSE的多线程中说过一个线程池,对照起来看
- 池,就是池化技术嘛,一个容器咯,而这个容器的作用就是:控制连接数据库的个数、设置url、username、password、连接数量不够进行扩容之类的容器嘛
- 数据库连接 -------> 执行完毕 ---------> 释放资源 整个过程是很消耗资源的。因此:连接池的真正作用就是 预先准备一些资源,这样一过来就可以进行连接操作了
- 在javaSE的多线程中说过一个线程池,对照起来看
- ①、什么是连接池?
- (2)、使用别人封装好的 ———— 连接池
- 怎么编写连接池?
- 很简单,只需要实现一个类就可以了 DataSource 去看一下这个类的源码( 是java.sql包下的 )
-
但是啊:有别人写好的东西,我们不用手写,因此:拿别人写好的东西来用一下咯
-
- 很简单,只需要实现一个类就可以了 DataSource 去看一下这个类的源码( 是java.sql包下的 )
- 怎么编写连接池?
- ②、别人写好的连接池有哪些?
- 最流行的就是:c3p0 、 dbcp 、 阿里巴巴的druid
- ②、别人写好的连接池有哪些?
- 简单聊一下这三个的理论知识
- druid 是淘宝 和 支付宝的必用数据库连接池 这玩意儿主要就是可以做到监控的功能,详细点就是如下:
- 对Oracle 和 MySQL做了特别的优化 如:Oracle 的 PS Cache 内存占用优化,MySql 的 ping 检测优化
- 使得分析 SQL 的抽象语法树很方便
- 简单 SQL 语句用时 10 微秒以内,复杂 SQL 用时 30 微秒
- 通过 Druid 提供的 Parser 可以在 JDBC 层拦截 SQL 做相应处理 ( 比如:分库分表,审计等 )
- 上面这些更细的知识点不懂没关系,只需要知道主要是搞监控机制的就行
- druid 是淘宝 和 支付宝的必用数据库连接池 这玩意儿主要就是可以做到监控的功能,详细点就是如下:
- 简单聊一下这三个的理论知识
- DBCP
- 是一个依赖 jakarta commons-pool 对象池机制的数据库连接池,DBCP,也是 Tomcat 使用的连接池组件
- DBCP
- c3p0
- 是一个开放源代码的 JDBC 连接池,它在 lib 目录中与 Hibernate 一起发布,,包括了实现 jdbc3 和 jdbc2 扩展规范说明的 Connection 和 Statement 池的 DataSources 对象
- c3p0
- 多说一嘴:DBCP和c3p0的区别
- ①、dbcp 没有自动回收空闲连接功能,c3p0 有自动回收空闲连接功能
②、两者对数据连接处理方式不同:c3p0 提供最大空闲时间,dbcp 提供最大连接数
③、c3p0 连接超过最大连接时间时,当前连接会断掉。dbcp 当连接数数超过最大连接数时,所有连接都会被断开
④、dbcp 它的原理是维护多个连接对象 Connection。在 web 项目要连接数据库时直接使用它维护对象进行连接,省去每次都要创建对象的麻烦,提高平效率和减少内存使用
⑤、c3p0 可以自动回收连接,dbcp 需要自己手动释放资源返回,不过 dbcp 效率比较高
- ①、dbcp 没有自动回收空闲连接功能,c3p0 有自动回收空闲连接功能
- 多说一嘴:DBCP和c3p0的区别
- 壹、一法通、万法通,先来玩一下DBCP
- ①、需要两个jar包
- 一个commons-dbcp 一个 commons-pool 想要什么版本自己去找,我的版本如下:
- commons-dbcp-1.4
- commons-pool-1.6
- 老规矩:把对应的jar包放到项目中去
- ①、需要两个jar包
- 壹、一法通、万法通,先来玩一下DBCP
- ②、需要设置配置文件
- 玩儿DBCP需要使用Properties进行编写配置
# 连接设置
# 注意:这个driverClassName必须用这个名字,别用什么driver就完了 因为:底层中找的就是这个名字
driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbc?characterEncoding = utf-8 & userUnicode = true & useSSL = true
username = root
password = 072413 # 初始化连接数量
initialSize = 10 # 最大连接数量
maxActive = 50 # 最大空闲连接数
maxIdle = 20 # 最小空闲连接数
minIdle = 5 # 超时等待时间 , 以毫秒为单位
maxWait = 60000 # 下面的设置要不要都无所谓 ## JDBC驱动建立连接时附带的连接属性的格式必须为这样 ———— 属性名 = property
## 另外:user 和 password两个属性会被明确地传递,因此:这里不需要包含他们
#connectionProperties = useUnicode = true ; characterEncoding = utf-8
#
## 指定有连接池所创建的连接的自动提交 auto-commit状态
#defaultAutoCommit = true
#
## driver default 指定由连接池所创建的连接的只读 read-only状态
## 但是:如果没有设置该值,则:setReadOnly方法不被调用
## 另外:某些驱动并不支持只读模式 如:informix
## 因此:这个不设置也行
## defaultReadOnly = ......
#
## driver default 指定有连接池所创建的连接的事务级别 transactionIsolation
## 可用值为下列之一:
## NONE , READ_UNCOMMITTED , READ_COMMITTED , REPEATABLE_READ
#defalutTransactionIsolation = READ_UNCOMMITTED
#
#
## 有需要的配置,没需要的就不配置这中间的东西,我嫌麻烦,不配置了,直接注释掉配置好了,那得用一下咯
- 玩儿DBCP需要使用Properties进行编写配置
- ②、需要设置配置文件
- 实体类还是用的person、util 和 dao需要做一下调整
- 封装DBCP工具类
package cn.xieGongZi.utils; import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties; public class JDBCUtil { // private static String driver; // 相应的这些也不要了
// private static String url;
// private static String username;
// private static String password; private static DataSource dataSource = null; // 提升作用域 为了获取链接嘛 static { // 这里就是去加载 DBCP_pool.properties 了
InputStream ins = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/DBCP_pool.properties"); Properties ppt = new Properties();
try {
ppt.load( ins ); // driver = ppt.getProperty("driver"); // 这一部分就不需要了,因为:在配置文件中配置了
// url = ppt.getProperty("url");
// username = ppt.getProperty("username");
// password = ppt.getProperty("password"); // Class.forName(driver); // 这里需要借助一个类来获取数据源 这是一个工厂模式 这个是用来创建对象的 它需要一个Properties对象,所以直接扔给它
dataSource = BasicDataSourceFactory.createDataSource(ppt);// 处理异常 这个东西获取的是一个Datasource数据源
} catch (Exception e) {
e.printStackTrace();
}
} // 封装获取数据库链接对象
public static Connection getConnection() throws SQLException {
// return DriverManager.getConnection(url, username, password); // 前面看源码不是看过datasource中自带获取连接吗,所以:这里直接通过DataSource获取连接
return dataSource.getConnection(); // 这样就把DBCP的工具类封装好了
} // 释放资源方法还是一样需要
// 提供释放资源的方法
public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象 if ( rs != null ){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( ps != null ){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( con != null ){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} }延伸一下:不是有一个BasicDataSourceFactory吗,看一下它的源码:
- 封装DBCP工具类
- 实体类还是用的person、util 和 dao需要做一下调整
- 修改dao层 其实就改两个地方 使用工具类调用那里
- 修改dao层 其实就改两个地方 使用工具类调用那里
- 测试:
- 测试:
- 贰、再来玩一下C3P0 其实玩法都一样,就是jar包不一样,然后获取数据源哪里不一样而已
- ①、需要的两个jar包
- c3p0 我的是:c3p0-0.9.5.2
- mchange-commons-java 我的是:mchange-commons-java-0.2.15
- ①、需要的两个jar包
- 贰、再来玩一下C3P0 其实玩法都一样,就是jar包不一样,然后获取数据源哪里不一样而已
- 老规矩 —— 编写实体类、放jar包
- 老规矩 —— 编写实体类、放jar包
- ②、编写配置文件 C3P0使用的是xml配置
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 数据库连接池 -->
<named-config name="mysql"> <!-- 这个named-config名字很重要,后面获取数据源需要它 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/blog</property>
<property name="user">root</property>
<property name="password">072413</property>
<!--当数据连接池不够的时候,每次增长的个数-->
<property name="acquireIncrement">5</property>
<!--初始的连接池个数-->
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">15</property>
<!--后面这两个可要可不要-->
<!--jdbc的标准参数 用于控制数据源里面的preparedStatement的数量-->
<property name="maxStatements">0</property>
<!--连接池内单个链接所拥有的最大的缓存statement数-->
<property name="maxStatementsPerConnoection">5</property>
</named-config>
</c3p0-config>
- ②、编写配置文件 C3P0使用的是xml配置
- ③、编写工具类、获取数据源
package cn.xieGongZi.utils; import com.mchange.v2.c3p0.ComboPooledDataSource; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; public class JDBCUtil { // 这里需要一个东西 ComboPooledDataSource 后面要通过这个去获取数据源
private static ComboPooledDataSource dataSource = null; static { // 获取数据源
dataSource = new ComboPooledDataSource("mysql"); // 这里的参数名字就是前面配置文件中提到的named-config名字
} // 只需要改以上部分就完了 // 这里和DBCP一样的
// 封装获取数据库链接对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
} // 释放资源方法还也是一样
// 提供释放资源的方法
public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象 if ( rs != null ){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( ps != null ){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if ( con != null ){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} }结果就不展示了
- ③、编写工具类、获取数据源
至此:JDBC的相关知识完毕,还有深层次的封装,就是使用preparedStatement对象时
将 增删改 和 释放资源 及 查 都进行封装了( 注:完美的查可以使用两种方法:一是接口回调、二是反射 )
另外一个就是ThreadLocal这个小东西,这个没什么好说的,就是一个看源码就懂的东西
附:ThreadLocal就是为了处理事务的( ThreadLocal支持泛型 ),所以就是为了保证Connection对象是同一个
这个ThreadLocal的核心方法就三个:get()、set()、remove()
另外:
IDEA连接数据库( 即:集成过去 )在右上角Database中
这样集成过去之后,就不用把IDEA和数据库来回切换了
感兴趣的自行去摸索一下
数据库之JDBC的更多相关文章
- 转!!各种数据库的jdbc驱动下载及连接方式
各种数据库驱动 数据库名称 下载地址 说明 Mysql http://www.mysql.com/products/connector/j/ Shipped. But need to download ...
- 各种数据库使用JDBC连接的方式
Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成.JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序.然而各个开 ...
- JAVA数据库编程(JDBC技术)-入门笔记
本菜鸟才介入Java,我现在不急着去看那些基本的语法或者一些Java里面的版本的特征或者是一些晋级的知识,因为有一点.Net的OOP编程思想,所以对于Java的这些语法以及什么的在用到的时候在去发现学 ...
- Java基础之MySQL数据库与JDBC
一.数据库 DBMS 数据库管理系统 是由多个程序构成的专门用来管理大量数据的计算机系统 Server 提供数据存储.检索.计算等服务的网络程序+系统服务 Notifier ...
- 数据库使用JDBC连接的方式
下面罗列了各种数据库使用JDBC连接的方式,可以作为一个手册使用. 1.Oracle8/8i/9i/10g/11g数据库(thin模式) Class.forName("oracle.jdbc ...
- Java操作数据库——在JDBC里使用事务
Java操作数据库——在JDBC里使用事务 摘要:本文主要学习了如何在JDBC里使用事务. 使用Connection的事务控制方法 当JDBC程序向数据库获得一个Connection对象时,默认情况下 ...
- Java操作数据库——使用JDBC连接数据库
Java操作数据库——使用JDBC连接数据库 摘要:本文主要学习了如何使用JDBC连接数据库. 背景 数据持久化 数据持久化就是把数据保存到可掉电式存储设备中以供之后使用.大多数情况下,特别是企业级应 ...
- 数据库持久化+JDBC数据库连接
数据持久化 数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称.数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型.XML.二进制流等. 瞬时状态 保 ...
- Java数据库编程(JDBC)
一.使用Java对数据库的操作步骤: 1.根据应用程序的数据库类型,加载相应的驱动: 2.连接到数据库,得到Connection对象: 3.通过Connection创建Statement对象: 4.使 ...
- 数据库 MySQL Jdbc JDBC的六个固定步骤
*0 案例: a)在JavaScript中使用正则表达式,在JS中正则表达式的定界符是:// var regexp = /^[0-9]+$/; if(regexp.test(nu ...
随机推荐
- PCB中,Solder Mask与Paste Mask有啥区别呢?
Solder Mask Layers: 即阻焊层.顾名思义,他的存在是为了防止PCB在过波峰焊的时候,不应涂锡的地方粘上锡. 可以简单理解为一个洞,该区域(洞)以外的地方,都不允许有焊锡,即只能涂绿油 ...
- 使用Keil下载Hex文件进STM32
前言 初学STM32时,是通过串口1把Hex文件下载进STM32的,需要一个串口模块,而且还要设置BOOT0和BOOT1电平,然后通过FlyMcu软件进行下载,这也是一种不错的方法,这里我要介绍的是使 ...
- STM32核心板焊接
焊接工具和材料 电烙铁及烙铁头介绍 电烙铁有很多种,常用的有内热式.外热式.恒温式和吸锡式,为了方便携带,建议使内热式电烙铁,且要带烙铁架和海绵,烙铁架用于放置电烙铁,海绵用于擦拭烙铁锡渣,因此海绵不 ...
- c++ get keyboard event
#include <string> #include <iostream> #include "windows.h" #include <conio. ...
- hdu 3863 No Gambling (不会证明,但是是对的,,)
题意: N=4时 规则: 双方每次可以连接自己颜色的两个点(相邻,长度为1),线和线不能交叉重叠. 蓝方要连接左右,红方要连接上下. 蓝方先.问谁先连接? 思路: 经过观察....蓝方胜....... ...
- Notepad++ 过滤注释行和空行
Notepad++ 删除指定字符开头的行的正则表达式 1.删除A之后的所有字符用:A.*$ 2.删除A之前的所有字符用:^([^s]*)A ####如果是其他字符就把A替换为其他字符 注释:如何是特殊 ...
- fiddler 手机+浏览器 抓包
用fiddler对手机上的程序进行抓包 前提: 1.必须确保安装fiddler的电脑和手机在同一个wifi环境下 备注:如果电脑用的是台式机,可以安装一个随身wifi,来确保台式机和手机在同一wi ...
- Oracle Error while trying to retrieve text for error ORA-01804
我在Linux上编译C++程序,有这个错误. 本机情况: Linux上Oracle的安装情况,服务器上有两个Client版本.我在Makefile中使用了高版本的动态库. 原因: 1.首先排查下 tn ...
- JVM 核心参数
JVM 内存相关的几个核心参数 参数部分看我笔记 https://note.youdao.com/s/Ch3awnVu JVM模板 1. ParNew + CMS 版 根据服务调整 -Xmx -X ...
- Part 35 AngularJS caseInsensitiveMatch and Inline Templates
In this video we will discuss 2 simple but useful features in Angular caseInsensitiveMatch Inline Te ...