索引

MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的的数据结构,提取句子主干,就可以得到作用的本质,索引是数据结构。

索引的分类

  • 主键索引:PRIMARY KEY

    • 唯一的标识,主键不可重复,只能由一个列作为索引
  • 唯一索引:UNIQUE KEY
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引
  • 常规索引:KEY/INDEX
    • 默认的,index,key关键字设置
  • 全文索引:FullText
    • 在特定的数据库引擎下才有
    • 快速定位数据

基础语法

  1. --索引的使用
  2. --在创建表的时候给字段增加索引 或创建完表后增加
  3. USE school
  4. SHOW INDEX FROM student1
  5. --增加索引
  6. ALTER TABLE `student1` ADD FULLTEXT INDEX `studentname`(`studentname`)
  7. --EXPLAIN 分析sql执行的状况
  8. EXPLAIN SELECT * FROM `student1` --非全文索引
  9. EXPLAIN SELECT * FROM student1 WHERE MATCH(studentname) AGAINST('韩')

测试索引

  1. --测试索引
  2. CREATE TABLE `app_user`(
  3. `id` INT(4) UNSIGNED NOT NULL AUTO_INCREMENT,
  4. `name` VARCHAR(20) DEFAULT'' COMMENT'用户姓名',
  5. `email` VARCHAR(20) NOT NULL COMMENT'用户邮箱',
  6. `phone` VARCHAR(20) DEFAULT'' COMMENT'用户电话',
  7. `gender` TINYINT(4) UNSIGNED DEFAULT'0' COMMENT'性别(1是男,2是女)',
  8. `password` VARCHAR(50) NOT NULL COMMENT '密码',
  9. `age` INT(3) DEFAULT'0' COMMENT'年龄',
  10. `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
  11. `update_name` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  12. PRIMARY KEY(`id`)
  13. )ENGINE INNODB DEFAULT CHARSET=utf8mb4 COMMENT'app用户表'
  14. --插入100万条数据
  15. --写函数之前必须写 标志
  16. DELIMITER $$
  17. CREATE FUNCTION mock_dat() #创建一个函数
  18. RETURNS INT
  19. BEGIN
  20. DECLARE num INT DEFAULT 1000000;
  21. DECLARE i INT DEFAULT 0;
  22. WHILE i<num DO
  23. INSERT INTO `app_user`(name,email,phone,gender,password,age)
  24. VALUES(CONCAT('用户',i),'813794474@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-1000000000)+1000000000))),
  25. FLOOR((RAND()*2)+1),UUID(),FLOOR(RAND()*100));
  26. SET i=i+1;
  27. END WHILE;
  28. RETURN i;
  29. END;
  30. --
  31. SELECT mock_dat();
  32. SELECT * FROM app_user WHERE name = '用户9999';
  33. EXPLAIN SELECT * FROM app_user WHERE name = '用户9999';
  34. EXPLAIN SELECT * FROM app_user WHERE name = '用户1';
  35. --创建索引 id_表名_字段名 on 表(字段)
  36. CREATE INDEX id_app_user_name ON app_user(`name`);
  37. SELECT * FROM app_user WHERE name = '用户9999';
  38. EXPLAIN SELECT * FROM app_user WHERE name = '用户9999';

索引在小数据的时候用处不大,在大数据的时候,区别十分明显。

索引原则

  • 索引不是越多越好
  • 不要对经常变动的数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加在常用来查询的字段上

索引的数据结构

Hash 类型的索引

Btree:innodb默认的数据结构

权限管理和备份

点击用户进去可以选择新增用户,在服务器权限中可以给用户设置不同的权限。

也可以使用SQL赋予每个用户权限

  1. --创建用户
  2. CREATE USER zhou IDENTIFIED BY '123456'
  3. --修改当前用户密码
  4. SET PASSWORD = PASSWORD('111111')
  5. --修改指定用户密码
  6. SET PASSWORD FOR zhou = password('111111')
  7. --重命名
  8. RENAME USER zhou TO zzzz
  9. --用户授权 授予全部的权限
  10. --ALL PRIVILEGES除了给别人授权都可以
  11. GRANT ALL PRIVILEGES ON *.* TO zzzz
  12. --查看指定用户权限
  13. SHOW GRANTS FOR zzzz
  14. --查看管理员权限
  15. SHOW GRANTS FOR root@localhost
  16. --root用户权限 GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
  17. --撤销权限
  18. REVOKE ALL PRIVILEGES *.* FROM zzzz
  19. --删除用户
  20. DROP zzzz

备份

为什么备份:

  • 保证重要的数据不丢失
  • 数据转移

MySQL数据库备份的方式

  • 直接拷贝物理文件

  • 在可视化工具中手动导出数据库

    • 在想要导出的表或者库中,右键选择转储sql文件
  • 使用命令行导出 mysqldump 命令行使用

    1. --mysqldump -h主机 -u用户名 -p密码 数据库 表名 >物理磁盘位置/文件名
    2. mysqldump -hlocalhost -uroot -p123456 school student1 > D:/a.sql
    3. --mysqldump -h主机 -u用户名 -p密码 数据库 表名1 表名2 >物理磁盘位置/文件名
    4. mysqldump -hlocalhost -uroot -p123456 school student1 subject > D:/b.sql
    5. --mysqldump -h主机 -u用户名 -p密码 数据库 >物理磁盘位置/文件名
    6. mysqldump -hlocalhost -uroot -p123456 school > D:/c.sql
    7. --导入表
    8. --登录
    9. mysql -uroot -p123456
    10. use school;
    11. sourse d/a.sql

    12. mysql -u用户名 -p密码 库名 表名<文件路径

规范数据库设计

当数据库比较复杂的时候,需要按规范设计。

糟糕的数据库设计:

  • 数据冗余,浪费空间
  • 数据插入和删除都麻烦【阿里巴巴开发手册 屏蔽使用外键】
  • 系统的性能差

良好的数据库设计:

  • 节省内存空间
  • 保证数据库的完整性
  • 性能好,便于开发

软件开发中关于数据库的设计

  • 分析需求:分析业务和需要处理的数据库的需求
  • 概要设计:设计关系图E-R图

设计数据库的步骤:(个人博客)

  • 收集信息,分析需求

    • 用户表(用户登录注册,个人信息,写博客,创建分类)
    • 分类表(文章分类,博客作者)
    • 文章表(文章信息)
    • 友链表(友链信息)
    • 评论表 (评论信息)
    • 自定义表(可选) (存储其他信息)
  • 标识实体(把需求写到字段)
  • 标识实体之间的关系
    • 写博客:user-->blog
    • 创建分类:user-->category
    • 友链:link
    • ...

三大范式

第一范式(1NF):原子性,要求数据库表的每一列都是不可分割的原子数据项。

第二范式(2NF):满足第一范式,非码属性必须完全依赖于候选码,确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关。即每张表只描述一件事情。

第三范式(3NF):满足第一第二范式,任何非主属性不依赖于其它非主属性(即消除传递依赖),第三范式需要确保数据表中每一列数据都与主键直接相关,而不能间接相关。

规范性和性能问题:(关联查询的表不得超过三张表 阿里规约)

  • 考虑商业化需求和目标(成本,用户体验),数据库的性能更加重要
  • 在规范性能需求的时候,需要适当考虑一下规范性
  • 在有些情况下,故意给表增加一些冗余字段(多表查询变为单表查询),提高效率
  • 故意增加一些计算列(从大数据量降为小数据量的一些查询)

JDBC

数据库驱动:应用程序和数据库之间需要有驱动来进行连接。

SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库)规范,俗称JDBC。

这些规范的具体实现由数据库厂商去做。

对于开发人员来说只需掌握JDBC接口的操作即可。

java.sql javac.sql

JDBC程序

创建lib目录,在lib下放入mysql-connector-java-5.1.47.jar,右击lib,add as library。

  • 加载驱动
  • 连接数据库 DriverManager
  • 获得执行sql的对象 statement
  • 获得返回的结果值
  • 释放连接
  1. package com.zr.lesson01;
  2. import java.sql.*;
  3. public class JdbcDemo01 {
  4. public static void main(String[] args) throws ClassNotFoundException, SQLException {
  5. //加载驱动
  6. Class.forName("com.mysql.jdbc.Driver");
  7. //用户信息和Url
  8. String url = "jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=false";
  9. String username = "root";
  10. String password = "123456";
  11. //连接成功 数据库对象 DriverManager驱动管理
  12. Connection connection = DriverManager.getConnection(url, username, password);
  13. //执行sql的对象
  14. Statement statement = connection.createStatement();
  15. //执行sql
  16. String sql = "select * from users";
  17. ResultSet resultSet = statement.executeQuery(sql); //返回的结果集
  18. while (resultSet.next()){
  19. System.out.println("id="+resultSet.getObject("id"));
  20. System.out.println("name="+resultSet.getObject("name"));
  21. System.out.println("pwd="+resultSet.getObject("password"));
  22. System.out.println("email="+resultSet.getObject("email"));
  23. System.out.println("birthday="+resultSet.getObject("birthday"));
  24. System.out.println("======================================");
  25. }
  26. //释放连接 耗资源 用完就关掉
  27. resultSet.close();
  28. statement.close();
  29. connection.close();
  30. }
  31. }
  32. //MySQL默认端口号3306
  33. //Oracle ---1521
  34. //jdbc:oracle:thin:@localhost:1521:sid
  1. connection.commit(); //事务提交
  2. connection.rollback(); //事务回滚
  3. connection.setAutoCommit(true); //开启事务提交
  4. statement.executeQuery(); //查询操作返回 resultset
  5. statement.executeUpdate(); //更新,插入,删除都用这个,返回一个受影响的行数
  6. statement.execute(); //执行任何sql
  7. resultset 查询的结果集,封装了所有的查询结果集
  8. resultSet.getObject();//在不知道列类型的情况下使用
  9. //知道列的指定类型
  10. resultSet.getString();
  11. resultSet.getInt();
  12. resultSet.getDate();
  13. resultSet.beforeFirst();//移动到最前面
  14. resultSet.afterLast();//移动到最后面
  15. resultSet.next();//移动到下一个
  16. resultSet.previous();//移动到前一个
  17. resultSet.absolute(row);//移动到指定行

Statement对象

jdbc中的statement对象用于向数据库发送sql语句,想完成对数据库的增删改查只需发送相应的sql语句即可。

executeUpdate执行完后,返回一个整数(即sql语句导致几行数据发生了变化)。

executeQuery执行完后,返回代表查询结果的resultset对象。

CRUD操作:create,使用Statement(sql)方法完成对数据库的添加操作,示例如下:

  1. Statement st = connection.createStatement;
  2. String sql = "insert into user(...) values(...) "
  3. int num = st.executeUpdate(sql);
  4. if(num>0){
  5. System.out.println("插入成功!")
  6. }

CRUD操作:delete,使用Statement(sql)方法完成对数据库的删除操作,示例如下:

  1. Statement st = connection.createStatement;
  2. String sql = "delete from user wherte id=1"
  3. int num = st.executeUpdate(sql);
  4. if(num>0){
  5. System.out.println("删除成功!")
  6. }

CRUD操作:update,使用Statement(sql)方法完成对数据库的修改操作,示例如下:

  1. statement st = connection.Statement;
  2. String sql = "update user set name=`` where id=1"
  3. int num = st.executeUpdate;
  4. if(num>0){
  5. System.out.println("修改成功!");
  6. }

CRUD操作:read,使用Statement(sql)方法完成对数据库的查询操作,示例如下:

  1. Statement st = connection.createStatement;
  2. String sql = "select * from user "
  3. Resultset rs = st.executeQuery(sql);
  4. if(rs.next()){
  5. //根据获取的数据类型,分别调用rs的相应方法映射到Java对象中
  6. }

工具类实现

先创建一个jdbcStudy数据库,再创建一个users用户表,表中的字段为id,name,password,emain,birthday

配置MySQL数据库文件,创建工具类

配置文件

  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/jdbcStudy?useunicode=true&characterEncoding=utf8&useSSL=false
  3. username=root
  4. password=123456

工具类

  1. package com.zr.lesson02.utils;
  2. //工具类
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.sql.*;
  6. import java.util.Properties;
  7. public class JdbcUtils {
  8. private static String driver = null;
  9. private static String url = null;
  10. private static String username = null;
  11. private static String password = null;
  12. static {
  13. try {
  14. //读取资源
  15. InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
  16. Properties properties = new Properties();
  17. properties.load(in);
  18. driver = properties.getProperty("driver");
  19. url = properties.getProperty("url");
  20. username = properties.getProperty("username");
  21. password = properties.getProperty("password");
  22. //驱动只用加载一次
  23. Class.forName(driver);
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. //获取连接
  29. public static Connection getConnection() throws SQLException {
  30. return DriverManager.getConnection(url,username,password);
  31. }
  32. //释放连接
  33. public static void release(Connection con, Statement st, ResultSet rs) throws SQLException {
  34. if (rs!=null){
  35. rs.close();
  36. }
  37. if (st!=null){
  38. st.close();
  39. }
  40. if (con!=null){
  41. con.commit();
  42. }
  43. }
  44. }

增加数据

  1. package com.zr.lesson02.utils;
  2. import java.sql.Connection;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. //插入数据
  7. public class TestInsert {
  8. public static void main(String[] args) throws Exception {
  9. Connection con = null;
  10. Statement st = null;
  11. ResultSet rs = null;
  12. try {
  13. con = JdbcUtils.getConnection(); //获取数据库连接
  14. st = con.createStatement();//创建执行sql的对象
  15. String sql = "insert into users values(5,'赵云','111111','111@qq.com','2020-01-01')";
  16. int i = st.executeUpdate(sql);//执行sql
  17. if (i>0){
  18. System.out.println("插入成功!");
  19. }
  20. } catch (SQLException throwables) {
  21. throwables.printStackTrace();
  22. }finally {
  23. JdbcUtils.release(con,st,rs);
  24. }
  25. }
  26. }

删除数据

  1. package com.zr.lesson02.utils;
  2. import java.sql.Connection;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. //删除数据
  7. public class TestDelete {
  8. public static void main(String[] args) throws SQLException {
  9. Connection con = null;
  10. Statement st = null;
  11. ResultSet rs = null;
  12. try {
  13. con = JdbcUtils.getConnection();//获取数据库连接
  14. st = con.createStatement();//创建执行sql的对象
  15. String sql = "delete from users where id=5";
  16. int i = st.executeUpdate(sql);
  17. if (i>0){
  18. System.out.println("删除创建!");
  19. }
  20. } catch (SQLException throwables) {
  21. throwables.printStackTrace();
  22. }finally {
  23. JdbcUtils.release(con,st,rs);
  24. }
  25. }
  26. }

修改数据

  1. package com.zr.lesson02.utils;
  2. import java.sql.Connection;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. //修改数据
  7. public class TestUpdate {
  8. public static void main(String[] args) throws SQLException {
  9. Connection con = null;
  10. Statement st = null;
  11. ResultSet rs = null;
  12. try {
  13. con = JdbcUtils.getConnection();//获取数据库连接
  14. st = con.createStatement();//创建执行sql的对象
  15. String sql = "update users set name='韩信' where id=4";
  16. int i = st.executeUpdate(sql);
  17. if (i>0){
  18. System.out.println("更新成功!");
  19. }
  20. } catch (SQLException throwables) {
  21. throwables.printStackTrace();
  22. }finally {
  23. JdbcUtils.release(con,st,rs);
  24. }
  25. }
  26. }

添加数据

  1. package com.zr.lesson02.utils;
  2. import java.sql.Connection;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. //查询数据
  7. public class TestSelect {
  8. public static void main(String[] args) throws SQLException {
  9. Connection con = null;
  10. Statement st = null;
  11. ResultSet rs = null;
  12. try {
  13. con = JdbcUtils.getConnection();//获取数据库连接
  14. st = con.createStatement();//创建执行sql的对象
  15. String sql = "select * from users";
  16. rs = st.executeQuery(sql);
  17. //if只能查出一条数据 这里查询所有用户信息使用while
  18. while (rs.next()){
  19. System.out.println("id="+rs.getInt("id"));
  20. System.out.println("name="+rs.getString("name"));
  21. System.out.println("password="+rs.getString("password"));
  22. System.out.println("email="+rs.getString("email"));
  23. System.out.println("birthday="+rs.getDate("birthday"));
  24. System.out.println("==========================");
  25. }
  26. System.out.println("查询成功!");
  27. } catch (SQLException throwables) {
  28. throwables.printStackTrace();
  29. }finally {
  30. JdbcUtils.release(con,st,rs);
  31. }
  32. }
  33. }

sql注入

sql存在漏洞,会被攻击导致数据泄露,sql会被拼接。

  1. package com.zr.lesson02.utils;
  2. import java.sql.Connection;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. //sql注入
  7. public class SqlInjection {
  8. public static void main(String[] args) throws SQLException {
  9. //正常登录 数据库中有的用户和密码
  10. //login("韩信","111111");
  11. //sql注入 会输出所有密码为123456的人的信息
  12. login("'or'1=1","123456");
  13. //sql注入 会查询所有信息
  14. //login("'or'1=1","'or='1=1");
  15. }
  16. //登录业务
  17. public static void login(String username,String password) throws SQLException {
  18. Connection con = null;
  19. Statement st = null;
  20. ResultSet rs = null;
  21. try {
  22. con = JdbcUtils.getConnection();//获取数据库连接
  23. st = con.createStatement();//创建执行sql的对象
  24. //select * from users where name=''or'1=1' and password='123456'
  25. //select * from users where name=''or'1=1' and password=''or'1=1'
  26. String sql = "select * from users where name='"+username+"' and password='"+password+"'";
  27. rs = st.executeQuery(sql);
  28. //if只能查出一条数据 这里查询所有用户信息使用while
  29. while (rs.next()){
  30. System.out.println("id="+rs.getInt("id"));
  31. System.out.println("name="+rs.getString("name"));
  32. System.out.println("password="+rs.getString("password"));
  33. System.out.println("email="+rs.getString("email"));
  34. System.out.println("birthday="+rs.getDate("birthday"));
  35. System.out.println("==========================");
  36. }
  37. } catch (SQLException throwables) {
  38. throwables.printStackTrace();
  39. }finally {
  40. JdbcUtils.release(con,st,rs);
  41. }
  42. }
  43. }

PreparedStatement对象

PreparedStatement可以防止sql注入,而且效率更高。实例如下:

增加数据:

  1. package com.zr.lesson03;
  2. import com.zr.lesson02.JdbcUtils;
  3. import java.util.Date;
  4. import java.sql.*;
  5. //PreparedStatement 插入
  6. public class TestInsert {
  7. public static void main(String[] args) throws SQLException {
  8. Connection con = null;
  9. PreparedStatement ps = null;
  10. ResultSet rs = null;
  11. try {
  12. con = JdbcUtils.getConnection();
  13. //区别
  14. String sql = "insert into users values(?,?,?,?,?)";//使用?占位符 代替参数
  15. ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
  16. //手动给参数赋值
  17. ps.setInt(1,5);
  18. ps.setString(2,"李白");
  19. ps.setString(3,"123333");
  20. ps.setString(4,"813794474@qq.com");
  21. //sql.Date 数据库 java.sql.date()
  22. //util.Date Java new date().gettime() 获得时间戳
  23. ps.setDate(5,new java.sql.Date(new Date().getTime()));
  24. //执行
  25. int i = ps.executeUpdate();
  26. if (i>0){
  27. System.out.println("插入成功!");
  28. }
  29. } catch (SQLException throwables) {
  30. throwables.printStackTrace();
  31. }finally {
  32. JdbcUtils.release(con,ps,rs);
  33. }
  34. }
  35. }

删除数据:

  1. package com.zr.lesson03;
  2. import com.zr.lesson02.JdbcUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. import java.util.Date;
  8. //PreparedStatement 删除
  9. public class TestDelete {
  10. public static void main(String[] args) throws SQLException {
  11. Connection con = null;
  12. PreparedStatement ps = null;
  13. ResultSet rs = null;
  14. try {
  15. con = JdbcUtils.getConnection();
  16. //区别
  17. String sql = "delete from users where id=?";//使用?占位符 代替参数
  18. ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
  19. //手动给参数赋值
  20. ps.setInt(1,5);
  21. //执行
  22. int i = ps.executeUpdate();
  23. if (i>0){
  24. System.out.println("删除成功!");
  25. }
  26. } catch (SQLException throwables) {
  27. throwables.printStackTrace();
  28. }finally {
  29. JdbcUtils.release(con,ps,rs);
  30. }
  31. }
  32. }

修改数据:

  1. package com.zr.lesson03;
  2. import com.zr.lesson02.JdbcUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. //PreparedStatement 修改
  8. public class TestUpdate {
  9. public static void main(String[] args) throws SQLException {
  10. Connection con = null;
  11. PreparedStatement ps = null;
  12. ResultSet rs = null;
  13. try {
  14. con = JdbcUtils.getConnection();
  15. //区别
  16. String sql = "update users set name = ? where id = ?;";//使用?占位符 代替参数
  17. ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
  18. //手动给参数赋值
  19. ps.setString(1,"关羽");
  20. ps.setInt(2,3);
  21. //执行
  22. int i = ps.executeUpdate();
  23. if (i>0){
  24. System.out.println("修改成功!");
  25. }
  26. } catch (SQLException throwables) {
  27. throwables.printStackTrace();
  28. }finally {
  29. JdbcUtils.release(con,ps,rs);
  30. }
  31. }
  32. }

查询数据:

  1. package com.zr.lesson03;
  2. import com.zr.lesson02.JdbcUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. //查询
  8. public class TestSelect {
  9. public static void main(String[] args) throws SQLException {
  10. Connection con = null;
  11. PreparedStatement ps = null;
  12. ResultSet rs = null;
  13. try {
  14. con = JdbcUtils.getConnection();
  15. String sql = "select * from users where id=?";
  16. ps = con.prepareStatement(sql);
  17. ps.setInt(1,3);
  18. rs = ps.executeQuery();
  19. if (rs.next()){
  20. System.out.println("name="+rs.getString("name"));
  21. System.out.println("password="+rs.getString("password"));
  22. }
  23. } catch (SQLException throwables) {
  24. throwables.printStackTrace();
  25. }finally {
  26. JdbcUtils.release(con,ps,rs);
  27. }
  28. }
  29. }

事务

要么都成功,要么都失败。

ACID原则:原子性(要么都成功,要么都失败),一致性(保持最终结果的一致性),持久性(一旦提交不可逆,持久到数据库),隔离性(多个进程互不干扰)。

隔离性的问题:

  • 脏读:一个事务读取了另一个没有提交的事务
  • 虚读(幻读):在一个事务内读取到了别人插入的数据,导致前后读出来的数据不一致
  • 不可重复读:在同一个事务内,重复读取了表中的数据,表数据发生了改变
  1. package com.zr.lesson04;
  2. import com.zr.lesson02.JdbcUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. //模拟转账成功
  8. public class TestTransaction {
  9. public static void main(String[] args) throws SQLException {
  10. Connection con = null;
  11. PreparedStatement st = null;
  12. ResultSet rs = null;
  13. try {
  14. con = JdbcUtils.getConnection();
  15. //关闭数据库的自动提交功能,自动开启事务
  16. con.setAutoCommit(false);
  17. //执行业务
  18. String sql1 ="update account set money = money-100 where name = 'libai'";
  19. st = con.prepareStatement(sql1);
  20. st.executeUpdate();
  21. String sql2 ="update account set money = money+100 where name = 'hanxin'";
  22. st = con.prepareStatement(sql2);
  23. st.executeUpdate();
  24. //业务完毕 提交事务
  25. con.commit();
  26. System.out.println("成功!");
  27. } catch (SQLException throwables) {
  28. try {
  29. con.rollback(); //失败就回滚事务
  30. } catch (SQLException e) {
  31. e.printStackTrace();
  32. }
  33. throwables.printStackTrace();
  34. }finally {
  35. JdbcUtils.release(con,st,rs);
  36. }
  37. }
  38. }

模拟转账失败

  1. package com.zr.lesson04;
  2. import com.zr.lesson02.JdbcUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. //模拟转账失败
  8. public class TestTransaction02 {
  9. public static void main(String[] args) throws SQLException {
  10. Connection con = null;
  11. PreparedStatement st = null;
  12. ResultSet rs = null;
  13. try {
  14. con = JdbcUtils.getConnection();
  15. //关闭数据库的自动提交功能,自动开启事务
  16. con.setAutoCommit(false);
  17. //执行业务
  18. String sql1 ="update account set money = money-100 where name = 'libai'";
  19. st = con.prepareStatement(sql1);
  20. st.executeUpdate();
  21. int x=1/0;//报错
  22. String sql2 ="update account set money = money+100 where name = 'hanxin'";
  23. st = con.prepareStatement(sql2);
  24. st.executeUpdate();
  25. //业务执行完毕 提交事务
  26. con.commit();
  27. System.out.println("成功!");
  28. } catch (Exception e) {
  29. //默认会自动回滚 也可以显式定义
  30. /* try {
  31. con.rollback(); //失败就回滚事务
  32. } catch (SQLException e2) {
  33. e2.printStackTrace();
  34. }*/
  35. e.printStackTrace();
  36. }finally {
  37. JdbcUtils.release(con,st,rs);
  38. }
  39. }
  40. }

数据库连接池

数据库连接---执行完毕---释放 连接释放是十分浪费系统资源的。

池化技术:准备一些预先的资源,过来连接已经准备好的。

编写连接池,实现一个接口DataSource。

开源数据源实现:

  • DBCP
  • C3P0
  • Durid(阿里巴巴)

DBCP

使用这些数据库连接池之后,我们在项目开发中就不需要编写数据库连接的代码了。

DBCP:lib下导入 commens-dbcp-1.4.jar和commens-pool-1.6.jar

创建dbconfig.properties文件

  1. #连接设置
  2. driverClassname=com.mysql.jdbc.Driver
  3. url=jdbc:mysql://localhost:3306/jdbcStudy?useunicode=true&characterEncoding=utf8&useSSL=false
  4. username=root
  5. password=123456
  6. #初始化连接
  7. initialSize=10
  8. #最大连接数量
  9. maxActive=50
  10. #最大空闲连接
  11. maxIdle=20
  12. #超时等待时间 毫秒
  13. maxWait=60000
  14. connectionProperties=useUnicode=true;characterEncoding=utf8
  15. defaultAutoCommit=true
  16. defaultReadOnly=
  17. defaultTransactionIsolation=READ_UNCOMMITTED

创建DBCP工具类

  1. package com.zr.lesson05;
  2. import org.apache.commons.dbcp.BasicDataSource;
  3. import org.apache.commons.dbcp.BasicDataSourceFactory;
  4. import javax.sql.DataSource;
  5. import java.io.InputStream;
  6. import java.sql.Connection;
  7. import java.sql.ResultSet;
  8. import java.sql.SQLException;
  9. import java.sql.Statement;
  10. import java.util.Properties;
  11. public class JdbcUtils_DBCP {
  12. private static DataSource dataSource = null;
  13. static{
  14. try{
  15. InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbconfig.properties");
  16. Properties properties = new Properties();
  17. properties.load(in);
  18. //创建数据源 工厂模式
  19. dataSource = BasicDataSourceFactory.createDataSource(properties);
  20. }catch (Exception e){
  21. e.printStackTrace();
  22. }
  23. }
  24. public static Connection getConnection() throws SQLException {
  25. return dataSource.getConnection(); //从数据源中获取连接
  26. }
  27. public static void release(Connection con, Statement st, ResultSet rs){
  28. if (con!=null){
  29. try {
  30. con.close();
  31. } catch (SQLException throwables) {
  32. throwables.printStackTrace();
  33. }
  34. }
  35. if (st!=null){
  36. try {
  37. con.close();
  38. } catch (SQLException throwables) {
  39. throwables.printStackTrace();
  40. }
  41. }
  42. if (rs!=null){
  43. try {
  44. con.close();
  45. } catch (SQLException throwables) {
  46. throwables.printStackTrace();
  47. }
  48. }
  49. }
  50. }

测试插入数据

  1. package com.zr.lesson05;
  2. import com.zr.lesson02.JdbcUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. import java.util.Date;
  8. public class TestDBCP {
  9. public static void main(String[] args) throws SQLException {
  10. Connection con = null;
  11. PreparedStatement ps = null;
  12. ResultSet rs = null;
  13. try {
  14. con = JdbcUtils_DBCP.getConnection();
  15. //区别
  16. String sql = "insert into users values(?,?,?,?,?)";//使用?占位符 代替参数
  17. ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
  18. //手动给参数赋值
  19. ps.setInt(1, 5);
  20. ps.setString(2, "李白");
  21. ps.setString(3, "123333");
  22. ps.setString(4, "813794474@qq.com");
  23. //sql.Date 数据库 java.sql.date()
  24. //util.Date Java new date().gettime() 获得时间戳
  25. ps.setDate(5, new java.sql.Date(new Date().getTime()));
  26. //执行
  27. int i = ps.executeUpdate();
  28. if (i > 0) {
  29. System.out.println("插入成功!");
  30. }
  31. } catch (SQLException throwables) {
  32. throwables.printStackTrace();
  33. } finally {
  34. JdbcUtils_DBCP.release(con, ps, rs);
  35. }
  36. }
  37. }

C3P0

C3P0:lib下导入c3p0-0.9.5.5.jar和mchange-commens-java-0.2.19.jar

先创建c3p0-config.xml文件,再创建JdbcUtils_C3P0工具类

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <c3p0-config>
  3. <!-- 默认配置,如果没有指定则使用这个配置 -->
  4. <default-config>
  5. <property name="driverClass">com.mysql.jdbc.Driver</property>
  6. <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy</property>
  7. <property name="user">root</property>
  8. <property name="password">123456</property>
  9. <property name="acquirIncrement">5</property>>
  10. <property name="initialPoolSize">10</property>
  11. <property name="maxPoolSize">20</property>
  12. <property name="minPoolSize">5</property>
  13. </default-config>
  14. <!-- 命名的配置,可以通过方法调用实现 -->
  15. <named-config name="Mysql">
  16. <property name="driverClass">com.mysql.jdbc.Driver</property>
  17. <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy</property>
  18. <property name="user">root</property>
  19. <property name="password">123456</property>
  20. <!-- 如果池中数据连接不够时一次增长多少个 -->
  21. <property name="acquireIncrement">5</property>
  22. <!-- 初始化数据库连接池时连接的数量 -->
  23. <property name="initialPoolSize">10</property>
  24. <!-- 数据库连接池中的最大的数据库连接数 -->
  25. <property name="maxPoolSize">25</property>
  26. <!-- 数据库连接池中的最小的数据库连接数 -->
  27. <property name="minPoolSize">5</property>
  28. </named-config>
  29. </c3p0-config>

创建C3P0工具类

  1. package com.zr.lesson05;
  2. import com.mchange.v2.c3p0.ComboPooledDataSource;
  3. import org.apache.commons.dbcp.BasicDataSourceFactory;
  4. import javax.sql.DataSource;
  5. import java.io.InputStream;
  6. import java.sql.Connection;
  7. import java.sql.ResultSet;
  8. import java.sql.SQLException;
  9. import java.sql.Statement;
  10. import java.util.Properties;
  11. public class JdbcUtils_C3P0 {
  12. private static ComboPooledDataSource dataSource = null;
  13. static{
  14. try{
  15. /*//代码配置
  16. dataSource = new ComboPooledDataSource();
  17. dataSource.setDriverClass();
  18. dataSource.setUser();
  19. dataSource.setPassword();
  20. dataSource.setJdbcUrl();
  21. dataSource.setMaxPoolSize();
  22. dataSource.setMinPoolSize();*/
  23. dataSource = new ComboPooledDataSource("Mysql");//配置文件写法
  24. //创建数据源 工厂模式
  25. }catch (Exception e){
  26. e.printStackTrace();
  27. }
  28. }
  29. public static Connection getConnection() throws SQLException {
  30. return dataSource.getConnection(); //从数据源中获取连接
  31. }
  32. public static void release(Connection con, Statement st, ResultSet rs){
  33. if (con!=null){
  34. try {
  35. con.close();
  36. } catch (SQLException throwables) {
  37. throwables.printStackTrace();
  38. }
  39. }
  40. if (st!=null){
  41. try {
  42. con.close();
  43. } catch (SQLException throwables) {
  44. throwables.printStackTrace();
  45. }
  46. }
  47. if (rs!=null){
  48. try {
  49. con.close();
  50. } catch (SQLException throwables) {
  51. throwables.printStackTrace();
  52. }
  53. }
  54. }
  55. }

测试插入代码

  1. package com.zr.lesson05;
  2. import java.sql.Connection;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.util.Date;
  7. public class TestC3P0 {
  8. public static void main(String[] args) throws SQLException {
  9. Connection con = null;
  10. PreparedStatement ps = null;
  11. ResultSet rs = null;
  12. try {
  13. con = JdbcUtils_C3P0.getConnection();
  14. //区别
  15. String sql = "insert into users values(?,?,?,?,?)";//使用?占位符 代替参数
  16. ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
  17. //手动给参数赋值
  18. ps.setInt(1, 6);
  19. ps.setString(2, "李白");
  20. ps.setString(3, "123333");
  21. ps.setString(4, "813794474@qq.com");
  22. //sql.Date 数据库 java.sql.date()
  23. //util.Date Java new date().gettime() 获得时间戳
  24. ps.setDate(5, new java.sql.Date(new Date().getTime()));
  25. //执行
  26. int i = ps.executeUpdate();
  27. if (i > 0) {
  28. System.out.println("插入成功!");
  29. }
  30. } catch (SQLException throwables) {
  31. throwables.printStackTrace();
  32. } finally {
  33. JdbcUtils_C3P0.release(con, ps, rs);
  34. }
  35. }
  36. }

结论:无论使用什么数据源,本质还是一样的,DataSource不变,方法就不会变。

MySql学习笔记--详细整理--下的更多相关文章

  1. MySql学习笔记--详细整理--上

    目录 MySql MySql安装 连接数据库 操作数据库 数据库的列类型 数据库的字段属性 创建数据库 修改删除表 数据管理 外键 DML语言 添加 修改 删除 DQL查询数据(重点) 查询 去重 w ...

  2. mysql学习笔记(window下简单使用+Navict)

    之前安装过mysql.最近刚好要重新翻出来看看 发现又忘记了那些命令.还是要百度.所以不如自己整理下 尽管网上有很多相关的介绍.当时想对的不如自己整理出来的舒服 首先是下载安装.网上有很多就不一一罗列 ...

  3. mysql学习笔记(Centos下rpm编译配置+远程访问)

    新工作以来,博主感觉天天都很忙,博客已经好久没有写了 从昨天开始弄centos服务器中搭建mysql5.6,由于yum最新版本只有5.1的所以折腾到现在 首先看看是否已安装过其他版本的mysql [r ...

  4. mysql basic operation,mysql总结,对mysql经常使用语句的详细总结,MySQL学习笔记

    mysql> select * from wifi_data where dev_id like "0023-AABBCCCCBBAA" ; 1.显示数据库列表.show d ...

  5. 【mysql学习笔记整理】

    /*mysql学习笔记整理*/ /*常用的数据库操作对象*/ #库的操作#创建#数据库的创建USE mysql;CREATE DATABASE db_x;#删除#删除数据库DROP DATABASE ...

  6. 一千行MySQL学习笔记 (转)

    出处:  一千行MySQL学习笔记 /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权 ...

  7. Mysql学习笔记(三)对表数据的增删改查。

    正文内容. 这一部分是最简单的,也是最麻烦的.简单是因为其实只包括增删该插四个部分.大体上看,增加数据.删除数据.修改数据.查询数据都不麻烦啊,我们日常都是常用的.这个谁不会呢?以前在培训机构学mys ...

  8. MySQL学习笔记-数据库文件

    数据库文件 MySQL主要文件类型有如下几种 参数文件:my.cnf--MySQL实例启动的时候在哪里可以找到数据库文件,并且指定某些初始化参数,这些参数定义了某种内存结构的大小等设置,还介绍了参数类 ...

  9. 数据库MySQL学习笔记高级篇

    数据库MySQL学习笔记高级篇 写在前面 学习链接:数据库 MySQL 视频教程全集 1. mysql的架构介绍 mysql简介 概述 高级Mysql 完整的mysql优化需要很深的功底,大公司甚至有 ...

随机推荐

  1. CentOS7 Nginx-1.10.3编译安装

    cat > nginx.sh <<EOF #停止apache,避免抢占端口号 systemctl stop httpd #创建nginx运行账户,非登录用户,不创建家目录 usera ...

  2. 计算机CPU是怎么认识代码的?

    先说一下半导体,啥叫半导体?就是介于导体和绝缘体中间的一种东西,比如二极管.   电流可以从A端流向C端,但反过来则不行.你可以把它理解成一种防止电流逆流的东西. 当C端10V,A端0V,二极管可以视 ...

  3. [分享] 通过修改CSS自定义chrome滚动条样式

    首先得说一句 我不懂CSS的写法之类的 这段CSS也是在网上找的 所以有更先进的需求的话 我肯定不能满足你们了 不好意思效果图在10楼有人上了 我这边不管怎么弄 上传图片都卡在96% 而且不翻wall ...

  4. src/plugins/Export2Excel.js(目录没有可以重建)

    第一步Install cnpm install file-saver 或者 yarn add file-saver cnpm install xlsx 或者 yarn add xlsx cnpm in ...

  5. Java学习的第四十二天

    1.例4.7弦截法求方程f(x)=x^3-5x^2+16x-80=0的根 import java.util.Scanner; import java.lang.*; public class cjav ...

  6. python数据类型互相转换

    类型转换 关注公众号"轻松学编程"了解更多. 主要针对几种存储工具:list.tuple.dict.set 特殊之处:dict是用来存储键值对的. 1.list 转换为set l1 ...

  7. React中useLayoutEffect和useEffect的区别

    重点: 1.二者函数签名相同,调用方式是一致的 2. 怎么简单进行选择: 无脑选择useEffect,除非运行效果和你预期的不一致再试试useLayoutEffect 区别详解:useEffect是异 ...

  8. [Codeforces 580D]Fizzy Search(FFT)

    [Codeforces 580D]Fizzy Search(FFT) 题面 给定母串和模式串,字符集大小为4,给定k,模式串在某个位置匹配当且仅当任意位置模式串的这个字符所对应的母串的位置的左右k个字 ...

  9. C#循环判断密码

      要求用户输入用户名和密码,只要不是admin.888888就一直提示用户名或密码错误,请重新输入 while (true) { Console.WriteLine("请输入帐号和密码&q ...

  10. Linux 基础命令及基本目录

    Linux 基础命令及基本目录 一.网卡 1.网卡配置文件路径 ​ /etc/sysconfig/network-scripts/ifcfg-eth0 配置文件: TYPE=Ethernet # 以太 ...