笔记内容学习来自B站狂神说java,狂神小迷弟一枚
课程链接: 快来点我,支持狂神..
要么都成功,要么都失败
将一组SQL放在一个批次中去执行
事务(Transaction)原则: ACID
原子性:
一组步骤要么都完成,要么都失败,不能只发生一个步骤。
一致性:
最终一致性,事务前后的数据完整性要保持一致(最后结果和预期计算的要一样)
隔离性:
针对多个用户同时操作,主要是排除其他事物对本次事务的影响。
持久性:
事务结束后的数据不随着外界原因导致数据失败,事务没有提交恢复到原状;事务已经提交,持久化到数据库。事务一旦提交就不可逆。
事务的隔离级别(出现的问题)
脏读:
指一个事务读取了另一个事务未提交的数据
不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。(不一定是错误,但是某些场合不对)
虚读(幻读):
指在一个事务内读取到别的事务插入的数据,导致前后读取不一致。
测试事务实现转账
--事务操作
-- MySql 是默认开启事务自动提交的
SET autocommit = 0 / 1 /* 关闭 / 开启 */
--手动处理事务
SET autocommit = 0 --关闭自动处理事务
--事务开启
START TRANSACTION --标记一个事物的开始,从这个之后的sql都在同一个事务内
INSERT XX
INSERT XX
--提交 : 持久化
COMMIT
--回滚 : 回到原来的样子
ROLLBACK
--事务结束
SET autocommit = 1 --开启提交
--了解补充
SAVEPOINT 保存点名字 --设置一个事务的保存点
ROLLBACK TO SAVEPOINT保存点名字 --回滚到保存点
--模拟场景 转账
--商店 数据库
CREATE DATEBASE shop CHARACTER SET utf8 COLLATE utf_8_general_ci
USE shop
-- 账户表
CREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VACHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
)ENGIN = INNODB DEFAULT CHARSET utf8
--插入 yzy 50000元 htk 3000元
INSERT INTO account VALUES (1,'YZY',500000.00),(2,'HTK',3000.00)
--模拟事务
SET autocommit = 0;
START TRANSACTION
UPDATE account SET money = money - 500 WHERE `name` = 'HTK' --HTK少500
UPDATE account SET money = money + 500 WHERE `name` = 'YZY' --YZY多500
COMMIT;
ROLLVACK;
SET autocommit = 1;
在java中事务就是一个方法
function(){
try(){
/*
正常业务代码
*/
commit() //成功提交
}catch(){
roollcack() //出现异常回滚
}
}
MySql 官方对索引的定义为:索引(index)是帮助MySql高效获取数据得数据结构。
提取句子主干,就可以得到索引的本质,索引是数据结构。
索引分类
索引的使用
/*显示所有索引*/
SHOW INDEX FROM student
/*增加一个全文索引 (索引名字)列名*/
ALTER TABLE school.student ADD FULLTEXT INDEX `studentName`(`studentName`)
/*EXPLAN 分析sql执行的状况*/
EXPLAN SELECT * FROM student; /*非全文索引(常规索引)*/
EXPLAN SELECT * FROM student WHERE MATCH(studentName) AGAINST('刘');
SQL 编程创建 100 万条数据 测试索引 (了解即可)
-- 创建表
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(50) DEFAULT '' COMMENT '用户手机',
`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男 1:女)',
`password` VARCHAR(50) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(`id`)
)ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COMMENT = 'app用户表'
-- 插入100万数据.
DELIMITER $$ -- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i
索引的数据结构
索引参考资料:https://blog.codinglabs.org/articles/theory-of-mysql-index.html
SQLyod 可视化管理
SQL 命令操作
-- 创建用户名和密码![在这里插入图片描述](https://img-blog.csdnimg.cn/20200417000455173.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1ODkxNTIw,size_16,color_FFFFFF,t_70)
CREATE USER xiaohu INENTIFIED BY '123456'
-- 修改密码
SET PASSWORD = PASSWORD('666666')
SET PASSWORD FOR xiaohu= PASSWORD('666666')
-- 重命名
RENAME USER xiaohu TO lwx
-- 授权(最高权限,但还不是root用户,因为并不能给别人权限)
GRANT ALL PRIVILEGES ON *.* TO rock
-- 查看权限
SHOW GRANTS FOR rock
SHOW GRANTS FOR root@localhost
-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM rock
为什么要备份:
MySql数据库备份的方式
直接拷贝物理文件
在Sqlyog这种可视化工具手动导出
使用命令行 导出 mysqldump
-- 导出
mysqldump -hlocalhost -uroot -p123456school student >D:/a.sql
--导入
--先登录
source <D:/a.sql
当数据库比较复杂的时候,我们就需要就需要设计了
糟糕的数据库设计
良好的数据库设计
软件开发中,关于数据库的设计
设计数据库的步骤(以个人博客为例子)
为什么需要数据规范化?
三大范式
第一范式(1NF)
原子性
需要保证每一列不可再分的原子数据项,不可以表中表。
第二范式(2NF)
消除非主属性对主码的部分依赖
在1NF的基础上,每张表只描述一件事情:既一张表中的每一列必须和该表的主键相关(可以使直接也可可是间接)。
第三范式(3NF)
规范性和性能有冲突
驱动:声卡,显卡,数据库
为什么需要数据库驱动
SUN公司为简化开发人员(对数据库的统一)操作,提供了一个(java操作数据库的)规范,俗称JDBC
这些规范的实现由具体的厂商去做。
对开发人员来说,只需要掌握JDBC接口操作即可。
创建测试数据库
1.新建测试数据库
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,'zhansan','123456','[email protected]','1980-12-12'),
(2,'lisi','123456','[email protected]','1980-7-04'),
(3,'wangwu','123456','[email protected]','1980-3-14');
2.在项目中导入数据库驱动jar包,记得ADD library
3.编写测试代码
package com.htk.jdbcstudy;
import java.sql.*;
import javax.sql.*;
//我的第一个jdbc程序
public class jdbcFirstDemo {
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 = "";
//3.连接成功, 数据库对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url,username,password);
//4.执行sql的对象 Statement
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("pwd=" + resultSet.getObject("password"));
System.out.println("email=" + resultSet.getObject("email"));
System.out.println("birthday=" + resultSet.getObject("birthday"));
System.out.println("---------------------------------------------------------------");
}
//6.释放连接
resultSet.close();;
statement.close();;
connection.close();
}
}
1、加载驱动
2、链接数据库 DriverManager
3、获得执行sql的对象 Statement
4、获取返回结果集
5、释放连接
DriverManager
Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动
//Connection 代表数据库
//数据库设置自动提交
//事务提交
//事务回滚
connection.rollback();
connection.commit();
connection.setAutoCommit(true);
URL
//协议://主机地址:端口号/数据库名?参数1&参数2&参数3
//mysql默认端口号3306
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
Statement执行sql的对象
String sql = "SELECT * FROM users"; //编写sql
statement.executeQuery(); //查询操作返回ResultSet
statement.execute();//执行任何sql
statement.executeUpdate(); //更新,插入,删除都是用这个,返回一个受影响的行数
ResultSet 查询的结果集:封装了所有查询结果
获得指定的数据类型
//获取指定类型
resultSet.getObject(); //在不知道列类型的情况使用
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
遍历
//查询出的结果就是像数组,可以自由移动
resultSet.next(); //向下移动
resultSet.beforeFirst(); //移动到最前面
resultSet.afterLast(); //移动到最后面
释放资源
//释放连接
resultSet.close();;
statement.close();;
connection.close();
//好资源,用完关闭
jdbc中的statement对象用于向数据库发送sql语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完成后,将会返回一个整数(既增删改查语句导致了数据库有多少行数据发生变化)。
Statement.executeQuery方法用于向数据库发送查询语句,excuteQuery方法返回代表查询结果的ResultSet对象。
CRUD 操作 - - - create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement st = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!");
}
CRUD 操作 - - - delete
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement st = connection.createStatement();
String sql = "delete from user";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!");
}
CRUD 操作 - - - update
使用executeUpdate(String sql)方法完成数据修改操作,示例操作:
Statement st = connection.createStatement();
String sql = "update user set name ='' where name = ''";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("修改成功!");
}
CRUD 操作 - - - query
使用executeQuery(String sql)方法完成数据添加操作,示例操作:
Statement st = connection.createStatement();
String sql = "SELECT * FROM users where id = 1";
ResultSet resultSet = st.executeQuery(sql);
while(resultSet.next()){
System.out.println("...");
}
代码实现
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=
package com.htk.jdbcstudy.lesson02.utils;
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 = JdbcUtils.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");
//1.驱动只用加载一次
Class.forName(driver);
}catch (Exception e){
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//释放资源
public static void release(Connection cont, 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 (cont!=null){
try{
cont.close();
}catch (SQLException e){
e.printStackTrace();
}
}
}
}
增
package com.htk.jdbcstudy.lesson02;
import com.htk.jdbcstudy.lesson02.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 cont = null;
Statement st = null;
ResultSet rs = null;
try {
cont = JdbcUtils.getConnection();
st = cont.createStatement();
String sql ="INSERT INTO users(id,`name`,`password`,email,birthday) VALUES(4,'htk','123456','[email protected]','1997-01-12')";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(cont,st,rs);
}
}
}
删
package com.htk.jdbcstudy.lesson02;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Testdelete {
public static void main(String[] args) {
Connection cont = null;
Statement st = null;
ResultSet rs = null;
try {
cont = JdbcUtils.getConnection();
st = cont.createStatement();
String sql ="DELETE FROM users WHERE id = 4";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(cont,st,rs);
}
}
}
改
package com.htk.jdbcstudy.lesson02;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Testupdate {
public static void main(String[] args) {
Connection cont = null;
Statement st = null;
ResultSet rs = null;
try {
cont = JdbcUtils.getConnection();
st = cont.createStatement();
String sql ="update users set `name`='yzy',email='[email protected]',birthday='1999-06-15' where id = 1 ";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("修改成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(cont,st,rs);
}
}
}
查
package com.htk.jdbcstudy.lesson02;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestQuery {
public static void main(String[] args) {
Connection cont = null;
Statement st = null;
ResultSet rs = null;
try {
cont = JdbcUtils.getConnection();
st = cont.createStatement();
String sql ="select * from users";
rs = st.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(cont,st,rs);
}
}
}
SQL注入
SQL存在漏洞,会被攻击导致数据泄露,SQL会被拼接。
package com.htk.jdbcstudy.lesson02;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQL注入 {
public static void main(String[] args) {
//正常登陆
login("yzy","123456");
//非正常登陆
login(" 'or '1=1","'or '1=1");
//"select * from users where `name` = ''or '1=1' and password = ''or '1=1'"
//name是空或者1=1则为真是恒成立的,说明可通过拼接字符串的漏洞来获取用户信息,有安全隐患。
}
//登陆业务
public static void login(String username,String password){
Connection cont = null;
Statement st = null;
ResultSet rs = null;
try {
cont = JdbcUtils.getConnection();
st = cont.createStatement();
String sql ="select * from users where `name` = '"+username+"' and password = '"+password+"'";
rs = st.executeQuery(sql);
while(rs.next()){
System.out.println("登陆成功");
System.out.print("账号:");
System.out.println(rs.getString("name"));
System.out.print("密码:");
System.out.println(rs.getString("password"));
System.out.println("====================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(cont,st,rs);
}
}
}
PreparedStatement 可以防止SQL注入,还可以调高效率
增
package com.htk.jdbcstudy.lesson03;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.*;
public class TestInsert {
public static void main(String[] args) {
Connection cont = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
cont = JdbcUtils.getConnection();
//区别是,使用? 占位符代替参数
String sql ="INSERT INTO users(id,`name`,`password`,email,birthday) VALUES(?,?,?,?,?)";
//预编译SQL,先写sql,然后不执行
pst = cont.prepareStatement(sql);
//手动设置参数
pst.setInt(1,5);
pst.setString(2,"yyy");
pst.setString(3,"123456");
pst.setString(4,"[email protected]");
//注意点 sql.Date 数据库 java.sql.Date()
// 和 util.Date java new Date().getTime()获得时间戳
pst.setDate(5,new java.sql.Date(new java.util.Date().getTime()));
//预编译完后直接调用执行方法
int num = pst.executeUpdate();
if(num > 0){
System.out.println("插入成功");
}
}catch(SQLException e){
e.printStackTrace();
}finally {
JdbcUtils.release(cont,pst,rs);
}
}
}
删
package com.htk.jdbcstudy.lesson03;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestDelete {
public static void main(String[] args) {
Connection cont = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
cont = JdbcUtils.getConnection();
//区别是,使用? 占位符代替参数
String sql ="DELETE FROM users WHERE id = ?";
//预编译SQL,先写sql,然后不执行
pst = cont.prepareStatement(sql);
//手动设置参数
pst.setInt(1,4);
//预编译完后直接调用执行方法
int num = pst.executeUpdate();
if(num > 0){
System.out.println("删除成功");
}
}catch(SQLException e){
e.printStackTrace();
}finally {
JdbcUtils.release(cont,pst,rs);
}
}
}
改
package com.htk.jdbcstudy.lesson03;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection cont = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
cont = JdbcUtils.getConnection();
//区别是,使用? 占位符代替参数
String sql ="update users set `name`=?,email=?,birthday=? where id = ?";
//预编译SQL,先写sql,然后不执行
pst = cont.prepareStatement(sql);
//手动设置参数
pst.setInt(4,1);
pst.setString(1,"yzy");
pst.setString(2,"[email protected]");
//注意点 sql.Date 数据库 java.sql.Date()
// 和 util.Date java new Date().getTime()获得时间戳
pst.setDate(3,new java.sql.Date(new java.util.Date().getTime()));
//预编译完后直接调用执行方法
int num = pst.executeUpdate();
if(num > 0){
System.out.println("修改成功");
}
}catch(SQLException e){
e.printStackTrace();
}finally {
JdbcUtils.release(cont,pst,rs);
}
}
}
查
package com.htk.jdbcstudy.lesson03;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestQuery {
public static void main(String[] args) {
Connection cont = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
cont = JdbcUtils.getConnection();
//区别是,使用? 占位符代替参数
String sql ="select * from users where id >= ?";
//预编译SQL,先写sql,然后不执行
pst = cont.prepareStatement(sql);
//手动设置参数
pst.setInt(1,1);
//预编译完后直接调用执行方法
rs = pst.executeQuery();
while(rs.next()){
System.out.println("账号:"+rs.getString("name")+" 密码:"+rs.getString("password"));
}
}catch(SQLException e){
e.printStackTrace();
}finally {
JdbcUtils.release(cont,pst,rs);
}
}
}
SQL注入
package com.htk.jdbcstudy.lesson02;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.*;
public class SQL注入 {
public static void main(String[] args) {
//正常登陆
login("yzy","123456");
//非正常登陆
login(" ''or 1=1","'' or 1=1");
//"select * from users where `name` = ''or '1=1' and password = ''or '1=1'"
//name是空或者1=1则为真是恒成立的,说明通过拼接字符串的漏洞导致被攻击。
}
//登陆业务
public static void login(String username,String password){
Connection cont = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
cont = JdbcUtils.getConnection();
cont = JdbcUtils.getConnection();
//区别是,使用? 占位符代替参数
//prepareStatement 防止 SQL注入的本质,就是把传递进来的参数当做字符。
//假设其中存在转义字符,会被直接转义。 比如说 ' 号会被直接转移 后期进阶 mybatis
String sql ="select * from users where `name`=? and `password`=?";
//预编译SQL,先写sql,然后不执行
pst = cont.prepareStatement(sql);
//手动设置参数
pst.setString(1,username);
pst.setString(2,password);
rs = pst.executeQuery();
while(rs.next()){
System.out.println("登陆成功");
System.out.print("账号:");
System.out.println(rs.getString("name"));
System.out.print("密码:");
System.out.println(rs.getString("password"));
System.out.println("====================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(cont,pst,rs);
}
}
}
打开右侧Datebase - - - 添加 Date Source - - - MySQL
在General 选项卡中输入数据库账号密码,test 连接
在Schemas选项卡中添加数据库,添加完成后可直接双击表查看,修改需要点击上方的DB确定修改
Console
切换数据库
隔离性产生的问题
脏读、不可重复读、虚读(幻读)
事务代码实现示例
package com.htk.jdbcstudy.lesson04;
import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction01 {
public static void main(String[] args) {
Connection cont = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
cont = JdbcUtils.getConnection();
//关闭额自动提交,就会开启事务
cont.setAutoCommit(false);
String sql1 = "update users set id =id + 10 where id < ?";
pst = cont.prepareStatement(sql1);
pst.setInt(1,2);
pst.executeUpdate();
// int x = 1/0;
String sql2 = "update users set id =id - 10 where id > ?";
pst = cont.prepareStatement(sql2);
pst.setInt(1,2);
pst.executeUpdate();
cont.commit();
System.out.println("提交事务成功");
}catch (SQLException e){
//若失败则默认回滚,不写rollback也会回滚。
try {
cont.rollback(); //失败回滚
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
}
数据库连接 — 执行完毕 — 释放
连接 – 释放这一流程十分系统资源
池化技术:准备一些预先的资源,过来就连接预先准备好的
编写连接池,只需要实现一个接口DateSource
开源数据源实现 (拿来即用)
DBCP
C3P0
Druid:阿里
DBCP
需要用到的jar包 commons-dbcp-1.4.jar、commons-pool-1.4.jar
package com.htk.jdbcstudy.lesson05;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils_DBCP {
private static DateSource dateSource = null;
static {
try{
//输入流
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//创建数据源 工厂模式 - - - > 创建
dateSource = BasicDateSourceFactory.createDateSource(properties);
//1.驱动只用加载一次
Class.forName(driver);
}catch (Exception e){
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dateSource.getConnection(); //从数据源中获取连接
}
//释放资源
public static void release(Connection cont, 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 (cont!=null){
try{
cont.close();
}catch (SQLException e){
e.printStackTrace();
}
}
}
}
//无任何变化,读源码学习
//原来为
cont = JdbcUtils.getConnection();
JdbcUtils.release(cont,pst,rs);
//修改后
cont = JdbcUtils_DBCP.getConnection();
JdbcUtils_DBCP.release(cont,pst,rs);
C3P0
需要用到的jar包 c3p0-0.9.5.5.jar 、mchange-commons-java-0.2.19.jar
结论
无论使用何种数据源,本质还是相同的
Apache大法好