Java连接Mysql实操(包含JDBC,C3P0数据源)

90 阅读9分钟

Mysql

JavaEE:企业级Java开发 Web

前端(页面:展示,数据!)

后台(连接点:链接数据库JDBC,连接前端(控制,控制视图跳转和前端(传递数据)))

数据库(存数据,Txt,Excel,Word)

只会写代码,,学到数据库,基本混口饭吃!

操作系统,数据结构与算法!当一个不错的程序员!

离散数据,数字电路,系统结构,编译原理,+实战经验,高级程序员 ~ 优秀的程序员

为什么学习数据库

  1. 岗位需求
  2. 现在的世界,大数据时代~ ,得数据库者的天下。
  3. 被迫需求:存数据
  4. 数据库是所有软件体系中最核心得存在 DBA

事务原则ACID原则

  1. 原子性(正对一个事务的,要么都完成要么都失败)
  2. 一致性(最终一致性,A跟B一共1000元,A有500,B也有500,A跟B互相转账,但是A和B无论怎么转账,总额必须是1000元,不能多也不能少)
  3. 隔离性 (多个用户同时操作数据库是隔离的不会互相影响)
    1. 脏读:指的是一个事务读取了另一个事务未提交的数据
    2. 不可重复读:在一个事务内部读取表中的某一行数据,多次读取结构不同(这个不一定是错误,只是某些场合不对)
    3. 虚读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致(一般是行影响,多了一行)
  4. 持久性
    1. 事务没有提交,恢复到原来
    2. 事务已经提交,持久化到数据库中的

数据库基本命令

mysql -uroot -p0000 --登录数据库
show databases      --查询所有数据库

--
user  xxx          --切换数据库 use数据库名
show tables        --查询当前数据库中所有得表
describe xxx   	   --显示表得所有表结构

--创建数据库
create database xxx --创建一个数据库

Sql注释:--
多行:
/*
qqqq
*/

数据xxx语言 CRUD增删改查! CV程序员 API程序员 CURD程序员(业务)

DDL 定义

DML 操作

DQL 查询

DCL 控制

索引

通过索引可以更快速的帮我们获取sql中的结果,没有用索引前0.5s,用了后0.0001s

索引的分类

在一个表中,主键索引只能有一个,唯一索引可以有多个

主键索引(PRIMARY KEY)

  1. 唯一标识,不可重复,只能有一个列作为主键

唯一索引(UNIQUE KEY)

  1. 避免重复的列出现,唯一索引可以重复,多个列都可以标识唯一索引

普通索引(Key/Index)

  1. 默认的,index,key关键字设置

全文索引(FullText)

  1. 在特定的数据库引擎下才有,MylSAM
  2. 快速定位数据
show index from xxx   --显示所有的索引信息
altel table 数据库.表 add FullText index ‘索引名’(‘列名’) --添加一个全文索引
--EXPLAIN 分析sql执行的状况
select * from 表名

测试索引

我们有一百万条数据

我们通过select * from xxx where name=9999,这时我们查询这条数据需要1-2秒

我们添加索引,再次执行,只需要0.0001秒,很快,因为我们在添加索引的时候,会自动在单独生成一个树

image-20220222102835653

索引在小数据的时候感觉不到用处,只有在数据量很大的时候才会体验到

索引原则:

索引不是越多越好

不要对经常变动的数据加索引(因为每次更新完,就要重新索引比较耗资源)

小数据量的表不需要加索引

索引一般加在常用来查询的字段上

索引默认类型是 Btree:innodb的默认数据结构

事务

要么都成功,要么都失败


1,sql执行 A给B转账

2,sql执行 B收到A的钱


image-20220222103432387

规范数据库设计

为什么需要设计

当数据库比较繁杂的时候,我们就需要设计了

糟糕的数据库设计:

  1. 数据冗余,浪费空间
  2. 数据库插入和清除都会麻烦/异常【屏蔽使用物理外键】
  3. 冗余的数据库肯定会照成程序的性能差

良好的数据库设计

  1. 节省空间
  2. 保证数据库的完整性
  3. 方便我们开发系统

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

  1. 分析需求:分析业务和需要处理的数据库的需求

  2. 概要设计:设计关系图E-R图

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

  1. 收集信息,分许需求
    1. 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
    2. 分类表(文章分类,谁创建的)
    3. 文章表(文章的信息)
    4. 有链表(友情链接)
    5. 自定义表(系统信息,某个关键的字,或者一些主字段)key:value(彩虹系统就是这样做的)

三大范式

为什么需要数据规范化

  1. 信息重复

  2. 更新异常

  3. 插入异常

    1. 无法正常显示信息
  4. 清除异常

    1. 丢失有效的信息

三大范式

  1. 第一范式(1NF)
    1. 原子性,保证每一列不可再分,简而言之,第一范式就是无重复的域
    2. 例如:image-20220222111428812
  2. 第二范式(2NF)
    1. 前提:满足第一范式
    2. 每张表只描述一件事情
    3. image-20220222111747868
  3. 第三范式(3NF)
    1. 前提:满足第二范式
    2. 第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
    3. image-20220222112000738

规范数据库的设计

规范性和性能的问题

阿里巴巴:关联查询的表不能超过三张表

  1. 考虑商业化的需求和目标,(成本,用户体验)
  2. 数据库的性能更加重要
  3. 在规范性能问题的时候,需要适当的考虑一下规范性!
  4. 故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)
  5. 故意增加一些计算列(从大数据量,降低为小数据量的查询:索引)

JDBC

数据库驱动

驱动:声卡,显卡,数据库驱动

image-20220222112951994

驱动包:javax.sql javax.sql,数据库驱动包

java操作jdbc

方法一(不安全)

package JDBC_test;

import java.sql.*;

public class Demo1 {

    public static void main(String[] args) throws Exception{
        //1.加载数据库驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.定义数据库账号和密码和url
        String username="root";
        String password="0000";
        String url="jdbc:mysql://localhost:3306/dsw";
        //3.链接成功,返回操作数据库的对象,connection代表数据库对象
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.执行sql的对象 statement执行sql的对象
        Statement statement = connection.createStatement();
        //5.用执行sql的对象去执行,可能存在结果,查看返回结果
        String sql="select * from shua_gift";
        ResultSet resultSet = statement.executeQuery(sql);
        //因为我们数据库中数据不止一个,而且resultset也没有下标,只能通过while循环来遍历
        while (resultSet.next()){
            //通过get方法获取结果集中的数据
            System.out.println(resultSet.getString("name"));
        }
        //6.执行完毕,释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}

方法二(安全)

package JDBC_test;

import java.sql.*;
import java.util.Properties;

public class Demo1 {

    public static void main(String[] args) throws Exception{
        //1.加载数据库驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.定义数据库账号和密码和url
        String username="root";
        String password="0000";
        String url="jdbc:mysql://localhost:3306/dsw";
        //3.链接成功,返回操作数据库的对象,connection代表数据库对象
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.用执行sql的对象去执行,可能存在结果,查看返回结果
        String sql="select * from shua_gift";
        //5.执行sql的对象 statement执行sql的对象
//        connection.prepareStatement();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preparedStatement.executeQuery();
        //因为我们数据库中数据不止一个,而且resultset也没有下标,只能通过while循环来遍历
        //next判断有没有下一个
        while (resultSet.next()){
            //通过get方法获取结果集中的数据
            System.out.println(resultSet.getString("name"));
        }
        //6.执行完毕,释放资源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

JDBC工具类

Jdbc_Utils

package Utils;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

/**
 * JDBC操作数据库工具类
 */
public class Jdbc_Utils {
    static String Driver;
    static String Url;
    static String UserName;
    static String PassWord;

    //在类加载的时候就执行这静态代码块,只会加载一次
    static{
        try {
            //获取配置文件
            InputStream inputStream = Jdbc_Utils.class.getClassLoader().getResourceAsStream("database.properties");
            //创建读取配置文件对象
            Properties properties = new Properties();
            //读取配置文件,将配置文件读取到properties对象中
            properties.load(inputStream);
            //将获取到的信息赋值给我们变量
            Driver = properties.getProperty("Driver");
            Url = properties.getProperty("url");
            UserName = properties.getProperty("username");
            PassWord = properties.getProperty("password");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取数据库链接对象
    public static Connection getConnection() throws Exception{
        //加载数据库驱动
        Class.forName(Driver);
        //返回数据库对象
        return DriverManager.getConnection(Url,UserName,PassWord);
    }
    //关闭数据库
    public static void isClose(PreparedStatement preparedStatement, Connection connection,ResultSet resultSet){
        if (preparedStatement!=null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

测试

package JDBC_test;

import Utils.Jdbc_Utils;

import java.sql.*;

public class Demo2 {
    public static void main(String[] args) throws Exception {
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        //获取数据库链接对象
        connection = Jdbc_Utils.getConnection();
        //执行sql语句
        String sql="insert into shua_gift(name,tid,rate)values(?,?,?)";
        //通过数据库对象预编译语句,这里并没有执行,只是预编译
        preparedStatement = connection.prepareStatement(sql);
        //给预编译的sql赋值
        preparedStatement.setObject(1,"星辰");
        preparedStatement.setObject(2,123);
        preparedStatement.setObject(3,431);
        //执行sql获取返回结果
        int i = preparedStatement.executeUpdate();
        //查询executeQuery返回的是ResultSet结果集,增删改全部使用executeUpdate返回的修改数据的数量
        //查询
        if (i>0){
            System.out.println("添加成功");
        }else{
            System.out.println("添加失败");
        }
        //关闭资源
        Jdbc_Utils.isClose(preparedStatement,connection,resultSet);
    }
}

SQL注入

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

我们可以使用prepareStatement对象来操作sql语句,可以防止sql注入,效率更高

事务

要么都成功,要么都失败

ACID原则

原子性:要么都成功,要么都失败 一致性:两个用户进行转账,转帐前和转账后两个用户余额总数不变 持久性:一旦提交,持久化到数据库

隔离性:

  1. 脏读:一个事务读取了另一个没有提交的事务
  2. 不可重复读:在一个事务内,重复读取表中的数据,表数据发生了改变,
  3. 幻读:在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致

代码实现

//关闭数据库自动提交,开启事务
        connection.setAutoCommit(false);

try{
    //业务逻辑
    .........
    //提交事务
	connection.commit();
}catch(Exception e){
    //如果try上面捕获异常后,就执行回滚
    connection.rollback();
}
    

数据源

C3P0

c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/dsw</property>
        <property name="user">root</property>
        <property name="password">0000</property>
        <property name="acquiredIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </default-config>
</c3p0-config>

c3p0工具类(工厂设计模式)

c3p0的对象是ComboPooledDataSource,我们返回他即可

他在我们自定义工具类中返回的对象变成c3p0

package Utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * JDBC操作数据库工具类
 */
public class C3p0_Utils {
    private static ComboPooledDataSource DataSource=null;
    //在类加载的时候就执行这静态代码块,只会加载一次
    static{
        try {
            //这里默认读取我们src目录下c3p0-config.xml中的配置文件
            //所以我们不需要在指定账号密码等等。
            DataSource = new ComboPooledDataSource("Mysql");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取数据库链接对象
    public static Connection getConnection() throws Exception{
    //这里返回我们c3p0对象,(工厂设计模式)
        return DataSource.getConnection();
    }
    //关闭数据库
    public static void isClose(PreparedStatement preparedStatement, Connection connection,ResultSet resultSet){
        if (preparedStatement!=null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}