MySql
文章目录
六.事务(面试高频题)
1.什么是事务
要么都成功,要么都失败
事件一:
1.SQL执行 A给B转账 A原有1000 B原有200,A给B转200
2.SQL执行 B收到A的钱 A变成800 B变成400
如果在执行1的时候,服务器卡了,导致B没收到
事务解决的就是这样的事件,
将一组SQL放在一个批次中去执行
事务原则:ACID原则 原子性 一致性 隔离性 持久性
原子性(Atomicity):要么都成功,要么都失败
一致性(Consistency):事务前后的数据完整性要保持一致
隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability):事务一旦提交则不可逆,被持久化到数据库中
事务的隔离级别:脏读,不可重复读,幻读
脏读:
指一个事务读取了另外一个事务未提交的数据
不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
虚读(幻读)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致。
2.事务
MySQL是默认开启事务自动提交的
SET autocommit =0; 关闭
SET autocommit =1; 开启(默认)
-- 手动处理事务
SET autocommit =0;
-- 事务开启(标记一个事务的开始,从这个之后的SQL都在同一个事务内):
START TRANSACTION;
-- 提交(commit):持久化(成功)
COMMIT
-- 回滚(rollback):回到原来的样子(失败)
ROLLBACK
-- 事务结束:
SET autocommit =1;
-- 了解
SAVEPOINT 保存点名;--设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名;-- 回滚到保存点
RELEASE SAVEPOINT 保存点名;-- 撤销保存点
模拟场景:
CREATE TABLE `account`(
`id` int(4) NOT NULL auto_increment,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE INNODB DEFAULT CHARSET=utf8;
INSERT INTO `account` (`name`,`money`) VALUES ('张三',800),('李四',200);
-- 转账事务
SET autocommit=0;
START TRANSACTION;
UPDATE `account` SET money=money-200 WHERE `name`='张三';
UPDATE `account` SET money=money+200 WHERE `name`='李四';
COMMIT; -- 提交
ROLLBACK; -- 回滚
SET autocommit=1;
七.索引
MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构。
1.索引的分类
主索引(PRIMARY KEY):唯一的标识,不可重复
唯一索引(UNIQUE KEY):避免列里的数据出现重复,多个列都可标识唯一索引
常规索引(KEY/INDEX):默认的,可以用index或key来设置
全文索引(FullText):最初MyISAM数据库支持,现在INNODB也有。用来快速定位数据
2.索引的使用
1.在创建表的同时给字段增加索引
2.创建完成后,增加索引
显示所有的索引信息
SHOW INDEX FROM `student`;
增加一个全局索引
ALTER TABLE `student` ADD FULLTEXT INDEX `studentname`(`studentname`);
第三种创建索引的方式,测试索引讲
CREATE INDEX id_app_user ON app_user(`name`);
分析SQL执行的状况
EXPLAIN SELECT * FROM student; -- 非全文索引
-- 全局索引在数据量少的时候,没有用 执行后没有结果
SELECT * FROM student WHERE MATCH(studentname) against('岳');
--
EXPLAIN SELECT * FROM student WHERE MATCH(studentname) against('岳');
3.测试索引
CREATE TABLE `app_user` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT'' COMMENT'用户昵称',
`email` VARCHAR(50) NOT NULL COMMENT'用户邮箱',
`phone` VARCHAR(20) DEFAULT'' COMMENT'手机号',
`gender` TINYINT(4) UNSIGNED DEFAULT '0'COMMENT '性别(0:男;1:女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT'0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT = 'app用户表'
-- 开启创建函数
SET GLOBAL log_bin_trust_function_creators=1;
DELIMITER $$
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i < num DO
INSERT INTO app_user(`name`, `email`, `phone`, `gender`, `password`, `age`)
VALUES(CONCAT('用户', i), CONCAT('100',i,'@qq.com'), CONCAT('13', FLOOR(RAND()*(999999999-100000000)+100000000)),FLOOR(RAND()*2+1),UUID(), FLOOR(RAND()*100));
SET i = i + 1;
END WHILE;
RETURN i;
END;
SELECT mock_data()$$ -- 执行此函数 生成一百万条数据
SELECT * FROM app_user WHERE `name`='用户9999'; -- 耗时0.945s
EXPLAIN SELECT * FROM app_user WHERE `name`='用户9999'; -- 遍历了整个表
-- 第三种创建索引的方式
CREATE INDEX id_app_user ON app_user(`name`);
SELECT * FROM app_user WHERE `name`='用户999999'; -- 耗时0.001s
EXPLAIN SELECT * FROM app_user WHERE `name`='用户999999'; -- 只查找了一条数据
索引在数据量小的时候,用处不大,但是在大数据的时候,区别十分明显
4.索引原则
- 索引不是越多越好
- 不要对经常变动的数据加索引
- 小数据量的表不需要加索引
- 索引一般加在常用来查询的字段上
索引的数据结构
hash类型的索引
Btree:InnoDB默认的默认数据结构
MySQL索引背后的数据结构及算法原理
八.权限管理
1.用户管理
命令操作:
用户表:mysql.user
本质还是对这张表进行操作
-- 创建用户:
CREATE USER mnm IDENTIFIED BY '123456';
-- 查看用户
SELECT user, host, authentication_string FROM USER WHERE USER='mnm';
-- 修改指定用户密码
ALTER USER `mnm`@`` IDENTIFIED BY '111222';
update user set authentication_string='123456' where user='mnm';
-- 用户重命名
RENAME USER `mnm`@`` TO `aaa`@``;
-- 删除用户
DROP USER mnm;
-- 查看root管理权限
SHOW GRANTS FOR root@localhost
九.数据库备份
目的:
保证重要的数据不丢失,有机会回滚
数据转移
MySQL数据库备份方式:
- 拷贝物理文件
- 在可视化工具中,导出文件
- 使用命令行导出
mysqldump -hlocalhost -uroot -proot school student >D:/a.sql
mysqldump -h 主机 -u 用户 -p密码 数据库 表名 > 到物理层地址/文件名
导入:
- 可视化工具运行 sql文件
- 命令行模式
登录MySQL
mysql -u账号 -p密码
十.规范数据库设计
1.为什么需要设计
当数据库比较复杂的时候,就需要设计了
糟糕的数据库设计:
- 数据冗余,浪费空间
- 数据库插入和删除都会麻烦、异常[屏蔽使用物理外键]
- 程序的性能差
良好的数据库设计:
- 节省内存空间
- 保证数据库的完整性
- 方便开发系统
软件开发中,关于数据库的设计
- 分析需求:分析业务和需要处理的数据库的需求
- 概要设计:设计关系图 E-R图
设计数据库的步骤(个人博客)
- 收集信息,分析需求
- 用户表(用户登录注销,用户的个人信息)
- 分类表(文章的分类)
- 文章表(文章的信息)
- 友链表(友链信息)
- 自定义表(系统信息,某个关键的字,一些主字段)
- 标识实体(把需求落实到实地)
- 标识实体之间的关系
2.三大范式
为什么需要数据规范化:
- 信息重复
- 更新异常
- 插入异常
- 无法正常显示信息
- 删除异常
- 丢失有效的信息
第一范式(1NF)
原子性:强调的是列的原子性,即数据库中每一列的字段都是单一属性,不可再分的。并且这个单一属性必须是由基本的数据类型所构成的,如整数、字符串等。
第二范式(2NF)
前提:满足第一范式
依赖性: 一张表必须有一个主键;非主键类必须完全依赖于主键,而不能只依赖主键的一部分。
第三范式(3NF)
前提:满足第一第二范式
非主键列必须直接依赖于主键,不能存在传递依赖。
规范性和性能的问题
关联查询的表不得超过三张表
- 考虑商业化的需求和目标(数据库的性能更加重要)
- 在规范性能的问题的时候,需要适当的考虑一下规范性
- 故意给某些表增加一些冗余的字段(从多表查询中变为单表查询)
- 故意增加一些计算列(从大数据量降低为小数据量查询)
十一.JDBC
1.数据库驱动
SUN公司为了简化开发人员的操作,提供了一个规范,俗称JDBC
这些规范的实现由具体的厂商去做
对于开发人员,只需要掌握JDBC的接口的操作即可
java.sql包
javax.sql包
导入数据库驱动
2.第一个JDBC程序
创建测试数据库
CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `jdbcStudy`;
CREATE TABLE `users`(
`id` INT PRIMARY KEY,
`NAME` VARCHAR(40),
`PASSWORD` VARCHAR(40),
`email` VARCHAR(60),
birthday DATE
);
INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES
(1,'zhangsan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')
编写测试代码
前置任务,在项目中添加JDBC的驱动,或配置maven
import java.sql.*;
//我的第一个jdbc程序
public class jdbc1 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");//固定写法
//2.用户信息和url
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username="root";
String password="root";
//3.连接成功
Connection connection = DriverManager.getConnection(url, username, password);
//4.执行sql的对象
Statement statement = connection.createStatement();
//5.执行sql的对象,执行sql
String sql="SELECT * FROM `users`;";
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集里封住了我们全部的查询出来的结果
while (resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));
System.out.println("NAME="+resultSet.getObject("NAME"));
System.out.println("PASSWORD="+resultSet.getObject("PASSWORD"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birthday="+resultSet.getObject("birthday"));
System.out.println("---------------------------");
}
//6.释放sql
resultSet.close();
statement.close();
connection.close();
}
}
步骤总结:
1.加载驱动
Class.forName(“com.mysql.cj.jdbc.Driver”);//MySQL8.0写法
2.连接数据库 DriverManager
String url=“jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false”;
MySQL8.0不需要建立ssl连接,所以将useSSL设置为false
mysql写法
jdbc:mysql//localhost:3306/数据库名?参数1&参数2&参数3
oralce写法:
觉得不错:oracle:thin@localhost:8521:sid
3.获得执行SQL的对象 Statement
connection 代表数据库,设置自动提交,事务提交,事务回滚…
Connection connection = DriverManager.getConnection(url, username, password);
connection.rollback();
connection.commit();
connection.setAutoCommit();
Statement、PepareStatement 都是执行SQL的对象
Statement statement = connection.createStatement();
statement.executeQuery();//查询操作,返回一个ResultSet
statement.execute();//执行任何sql
statement.executeUpdate();//更新,插入,删除都是用这个,返回一个受影响的总数
4.获得返回的结果集
ResultSet 查询的结果集,只有查询才有,封装了所有的查询结果
resultSet.getObject();//在不知道类型的时候,就是用getObject
//如果知道列的类型就使用指定的类型
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
resultSet.getObject();
遍历,指针
resultSet.previous();//移动到最前面
resultSet.afterLast();//移动到最后面
resultSet.next();//移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行
5.释放连接
释放资源必须做,非常占用内存
resultSet.close();
statement.close();
connection.close();//耗资源
3.statement对象
Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可.
Statement对象的executeUpdate方法, 对于向数据库发送增删改的SQL语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化).
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象.
DRUD操作-create
使用executeUpdate(string sql)方法完成数据添加操作,示例如下
Statement statement = connection.createStatement();
String sql="insert into user(...) values(...);";
int num=statement.executeUpdate(sql);
if(num>0){
System.out.println("插入成功");
}
CRUD操作-delete
使用executeUpdate(string sql)方法完成数据删除操作,示例如下
Statement statement = connection.createStatement();
String sql="delete from user where id=1;";
int num=statement.executeUpdate(sql);
if(num>0){
System.out.println("删除成功");
}
CRUD操作-update
使用executeUpdate(string sql)方法完成数据修改操作,示例如下
Statement statement = connection.createStatement();
String sql="update user set name='' where name='';";
int num=statement.executeUpdate(sql);
if(num>0){
System.out.println("修改成功");
}
CRUD操作-read
使用executeQuery(string sql)方法完成数据查询操作,示例操作:
Statement statement = connection.createStatement();
String sql="SELECT * FROM `users`;";
esultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
//根据获取列的数据类型,分别调用rs的相应方法映射到Java对象中
}
4.代码实现:
jdbcUtils文件
import com.mysql.cj.jdbc.JdbcConnection;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class jdbcUtils {
private static String driver=null;
private static String url=null;
private static String username=null;
private static String password=null;
static {
try {
InputStream in = JdbcConnection.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.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(Connection conn, 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(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
db.properties文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=root
TestInsert文件
其他的几乎不变
import lession2.utils.jdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn=jdbcUtils.getConnection();//获得数据库连接
st=conn.createStatement();//获得SQL执行对象
String sql="INSERT INTO `users` (`NAME`,`PASSWORD`,`email`,`birthday`) VALUES ('zhaoliu','123456','zhaoliu@sina.com','1973-3-23')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
jdbcUtils.release(conn,st,rs);
}
}
}
SQL注入的问题
sql存在漏洞,会被攻击导致数据泄露,SQL会被拼接
import lession2.utils.jdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SqlInject {
public static void main(String[] args) {
//login("赵六","123456");//正常登陆
login(" 'or'1=1"," 'or'1=1");//拼接sql
}
public static void login(String name,String password){
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn= jdbcUtils.getConnection();//获得数据库连接
st=conn.createStatement();//获得SQL执行对象
String sql="SELECT * FROM `users` WHERE `NAME`='"+name+"' AND `PASSWORD`='"+password+"';";
rs = st.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("NAME"));
System.out.println(rs.getString("PASSWORD"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
jdbcUtils.release(conn,st,rs);
}
}
}
发现Statement对象是不安全的
5.PreparedStatement对象
目的:防止SQL注入,而且效率更高
import lession2.utils.jdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class SqlInject {
public static void main(String[] args) {
//login("赵六","123456");//正常登陆
login("''or'1=1","''or'1=1");//拼接sql
}
public static void login(String name,String password){
Connection conn=null;
PreparedStatement st=null;
//PreparedStatement防止SQL注入的本质,就是把传递进来的参数当做字符
//假设其中存在转义字符,直接忽略,引号会被转义
ResultSet rs=null;
try {
conn= jdbcUtils.getConnection();//获得数据库连接
String sql="SELECT * FROM `users` WHERE `NAME`=? AND `PASSWORD`=?;";
st=conn.prepareStatement(sql);//获得SQL执行对象
st.setString(1,name);
st.setString(2,password);
rs = st.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("NAME"));
System.out.println(rs.getString("PASSWORD"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
jdbcUtils.release(conn,st,rs);
}
}
}
文件:TestInsert,使用PreparedStatement
import lession2.utils.jdbcUtils;
import java.sql.*;
import java.util.Date;
public class TestInsert {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try {
conn = jdbcUtils.getConnection();
//区别,使用问号占位符代替参数
String sql="INSERT INTO `users` (`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (?,?,?,?);";
pst = conn.prepareStatement(sql);
//手动给参数赋值
pst.setString(1,"zhaoliu");
pst.setString(2,"123456");
pst.setString(3,"zhaoliu@qq.com");
//date类型,注意是sql.date 还是util.date
//sql.date是数据库用的,util.date是Java用的
//new Date().getTime() 获得时间戳
pst.setDate(4,new java.sql.Date(new Date().getTime()));
int i = pst.executeUpdate();
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
jdbcUtils.release(conn,pst,rs);
}
}
}
6.事务 (PreparedStatement)
代码实现:
1.开启事务:conn.setAutoCommit(false);
2.一组业务执行完毕,提交事务
3.可以在catch语句中显示定义回滚语句,但默认失败就会回滚
import lession2.utils.jdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction1 {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try {
conn = jdbcUtils.getConnection();
//关闭数据库的自动提交功能,自动开启事务
conn.setAutoCommit(false);
String sql1="update account set money=money-100 where name='张三';";
pst = conn.prepareStatement(sql1);
pst.executeUpdate();
int x=1/0;//人为制造错误,促使回滚
String sql2="update account set money=money+100 where name='李四';";
pst = conn.prepareStatement(sql2);
pst.executeUpdate();
//业务完毕,提交业务
conn.commit();
System.out.println("成功");
} catch (Exception throwables) {
try {
conn.rollback();//如果失败,则回滚
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}
finally {
jdbcUtils.release(conn,pst,rs);
}
}
}
7.数据库连接池
数据库连接–执行完毕–释放
连接–释放十分浪费系统资源
池化技术:准备一些预先的资源,过来就连接预先准备好的
比如常用连接数:10
配置为:
最小连接数:10
最大连接数:15 (业务最高承载上限)
排队等待
等待超时:100ms
编写连接池,实现一个接口 DataSource
开源数据源实现:DBCP C3P0 Druid
是用来这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了.
DBCP代码修改实现:
改写后的TestInsert
需要具备的jar包:commons-dbcp commons-pool最新即可
我使用的是commons-dbcp2,commons-pool2
import lession5.utils.jdbcUtils_dbcp;
import java.sql.*;
import java.util.Date;
public class TestDBCP {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try {
conn = jdbcUtils_dbcp.getConnection();
//区别,使用问号占位符代替参数
String sql="INSERT INTO `users` (`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (?,?,?,?);";
pst = conn.prepareStatement(sql);
//手动给参数赋值
pst.setString(1,"zhaoliu");
pst.setString(2,"123456");
pst.setString(3,"zhaoliu@qq.com");
//date类型,注意是sql.date 还是util.date
//sql.date是数据库用的,util.date是Java用的
//new Date().getTime() 获得时间戳
pst.setDate(4,new java.sql.Date(new Date().getTime()));
int i = pst.executeUpdate();
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
jdbcUtils_dbcp.release(conn,pst,rs);
}
}
}
jdbcUtils_dbcp文件配置
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class jdbcUtils_dbcp {
private static BasicDataSource dataSource = null;
static {
try {
InputStream in = jdbcUtils_dbcp.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//创建数据源 工厂模式-->创建
dataSource = BasicDataSourceFactory.createDataSource(properties);
}catch (Exception e){
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();//从数据源中获取连接
}
//释放连接
public static void release(Connection conn, 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(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
dbcpconfig.properties文件配置
#连接设置 这里面的名字是DBCP数据源中定义好的
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
maven配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>jdcbstudy</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
C3P0代码修改实现:
jdbcUtils_C3P0文件配置
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class jdbcUtils_C3P0 {
private static ComboPooledDataSource dataSource = null;
static {
try {
//创建数据源 工厂模式-->创建
dataSource= new ComboPooledDataSource();
}catch (Exception e){
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();//从数据源中获取连接
}
//释放连接
public static void release(Connection conn, 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(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
TestC3P0文件配置
import lession5.utils.jdbcUtils_C3P0;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class TestC3P0 {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try {
conn = jdbcUtils_C3P0.getConnection();
//区别,使用问号占位符代替参数
String sql="INSERT INTO `users` (`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (?,?,?,?);";
pst = conn.prepareStatement(sql);
//手动给参数赋值
pst.setString(1,"张三");
pst.setString(2,"123456");
pst.setString(3,"zhangsan@qq.com");
//date类型,注意是sql.date 还是util.date
//sql.date是数据库用的,util.date是Java用的
//new Date().getTime() 获得时间戳
pst.setDate(4,new java.sql.Date(new Date().getTime()));
int i = pst.executeUpdate();
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
jdbcUtils_C3P0.release(conn,pst,rs);
}
}
}
c3p0-config.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--
c3p0的缺省(默认)配置
如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource();"这样写就表示使用的是c3p0的缺省(默认)-->
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&uesSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
</c3p0-config>
maven文件配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>jdcbstudy</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>mchange-commons-java</artifactId>
<version>0.2.20</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
总结:
无论使用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变
Druid会在springboot中讲解