Mysql
JavaEE:企业级Java开发 Web
前端(页面:展示,数据!)
后台(连接点:链接数据库JDBC,连接前端(控制,控制视图跳转和前端(传递数据)))
数据库(存数据,Txt,Excel,Word)
只会写代码,,学到数据库,基本混口饭吃!
操作系统,数据结构与算法!当一个不错的程序员!
离散数据,数字电路,系统结构,编译原理,+实战经验,高级程序员 ~ 优秀的程序员
为什么学习数据库
- 岗位需求
- 现在的世界,大数据时代~ ,得数据库者的天下。
- 被迫需求:存数据
- 数据库是所有软件体系中最核心得存在 DBA
事务原则ACID原则
- 原子性(正对一个事务的,要么都完成要么都失败)
- 一致性(最终一致性,A跟B一共1000元,A有500,B也有500,A跟B互相转账,但是A和B无论怎么转账,总额必须是1000元,不能多也不能少)
- 隔离性 (多个用户同时操作数据库是隔离的不会互相影响)
- 脏读:指的是一个事务读取了另一个事务未提交的数据
- 不可重复读:在一个事务内部读取表中的某一行数据,多次读取结构不同(这个不一定是错误,只是某些场合不对)
- 虚读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致(一般是行影响,多了一行)
- 持久性
- 事务没有提交,恢复到原来
- 事务已经提交,持久化到数据库中的
数据库基本命令
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)
- 唯一标识,不可重复,只能有一个列作为主键
唯一索引(UNIQUE KEY)
- 避免重复的列出现,唯一索引可以重复,多个列都可以标识唯一索引
普通索引(Key/Index)
- 默认的,index,key关键字设置
全文索引(FullText)
- 在特定的数据库引擎下才有,MylSAM
- 快速定位数据
show index from xxx --显示所有的索引信息
altel table 数据库.表 add FullText index ‘索引名’(‘列名’) --添加一个全文索引
--EXPLAIN 分析sql执行的状况
select * from 表名
测试索引
我们有一百万条数据
我们通过select * from xxx where name=9999,这时我们查询这条数据需要1-2秒
我们添加索引,再次执行,只需要0.0001秒,很快,因为我们在添加索引的时候,会自动在单独生成一个树
索引在小数据的时候感觉不到用处,只有在数据量很大的时候才会体验到
索引原则:
索引不是越多越好
不要对经常变动的数据加索引(因为每次更新完,就要重新索引比较耗资源)
小数据量的表不需要加索引
索引一般加在常用来查询的字段上
索引默认类型是 Btree:innodb的默认数据结构
事务
要么都成功,要么都失败
1,sql执行 A给B转账
2,sql执行 B收到A的钱
规范数据库设计
为什么需要设计
当数据库比较繁杂的时候,我们就需要设计了
糟糕的数据库设计:
- 数据冗余,浪费空间
- 数据库插入和清除都会麻烦/异常【屏蔽使用物理外键】
- 冗余的数据库肯定会照成程序的性能差
良好的数据库设计
- 节省空间
- 保证数据库的完整性
- 方便我们开发系统
软件开发中,关于数据库的设计
-
分析需求:分析业务和需要处理的数据库的需求
-
概要设计:设计关系图E-R图
设计数据库的步骤(个人博客)
- 收集信息,分许需求
- 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
- 分类表(文章分类,谁创建的)
- 文章表(文章的信息)
- 有链表(友情链接)
- 自定义表(系统信息,某个关键的字,或者一些主字段)key:value(彩虹系统就是这样做的)
三大范式
为什么需要数据规范化
-
信息重复
-
更新异常
-
插入异常
- 无法正常显示信息
-
清除异常
- 丢失有效的信息
三大范式
- 第一范式(1NF)
- 原子性,保证每一列不可再分,简而言之,第一范式就是无重复的域
- 例如:
- 第二范式(2NF)
- 前提:满足第一范式
- 每张表只描述一件事情
- 第三范式(3NF)
- 前提:满足第二范式
- 第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
规范数据库的设计
规范性和性能的问题
阿里巴巴:关联查询的表不能超过三张表
- 考虑商业化的需求和目标,(成本,用户体验)
- 数据库的性能更加重要
- 在规范性能问题的时候,需要适当的考虑一下规范性!
- 故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)
- 故意增加一些计算列(从大数据量,降低为小数据量的查询:索引)
JDBC
数据库驱动
驱动:声卡,显卡,数据库驱动
驱动包: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原则
原子性:要么都成功,要么都失败 一致性:两个用户进行转账,转帐前和转账后两个用户余额总数不变 持久性:一旦提交,持久化到数据库
隔离性:
- 脏读:一个事务读取了另一个没有提交的事务
- 不可重复读:在一个事务内,重复读取表中的数据,表数据发生了改变,
- 幻读:在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致
代码实现
//关闭数据库自动提交,开启事务
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();
}
}
}
}