MySQL(二)

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&amp;characterEncoding=utf8&amp;uesSSL=false&amp;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中讲解

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
对于MySQL进制安装,可以按照以下步骤进行操作: 1. 下载MySQL进制文件,并将其移动到目标目录。根据引用,可以使用命令`mv mysql-5.7.30-linux-glibc2.12-x86_64 /home/mysql2/mysql`将MySQL进制文件移动到`/home/mysql2/mysql`目录中。 2. 创建MySQL的数据目录。可以使用命令`mkdir /usr/local/mysql`创建MySQL的数据目录。根据引用,可以使用命令`mv mysql-5.7.35-linux-glibc2.12-x86_64 /usr/local/mysql`将MySQL进制文件移动到`/usr/local/mysql`目录中。 3. 设置MySQL数据目录的所有者和权限。根据引用,可以使用命令`chown -R mysql2.mysql2 /Lcdmp3_mysqldata/ /home/mysql2`将数据目录的所有者设置为`mysql2`,组设置为`mysql2`。 请注意,以上步骤仅为示例,具体的安装步骤可能因MySQL版本或操作系统的差异而有所不同。在进行MySQL进制安装之前,请确保已阅读并遵循官方文档或安装指南以确保正确安装和配置MySQL。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [进制方式安装mysql](https://blog.csdn.net/qq_26711103/article/details/128559643)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [MySQL进制安装](https://blog.csdn.net/LFCuiYs/article/details/120830896)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值