MySQL是关系型(SQL)数据库。5.7稳定
数值
tinyint 1个字节
smallint 两个字节
mediumint 三个字节
int 四个字节
bigint 八个字节
float 四个字节
double 八个字节
decimal 字符串形式的浮点数
字符串
char 字符串 0-255varchar 可变字符串 0-65535tinytext 2^8-1text 2^16-1时间日期
date YYYY-MM-DDtime HH:mm:ssdatetime YYYY-MM-DD HH:mm:sstimestamp 时间戳 1970.1.1到现在的秒数year 年份null
没有值,未知,不要用null进行运算
Unsigned:
无符号整数限制不能为负数zerofill:
0填充不足位数,用0填充自增:
AUTO_INCREMENT非空:
NOT NULL默认:
不指定该列时,则使用该默认值DEFAULT增加
insert into `person`(`age`,`name`) values(1,'长江一号'),(15,'长江十五号')删除
-- 删除指定记录 delete from `person` where `name` = '长江七号' -- 清空表 delete from `person` -- 清空表 truncate table `person`delete和truncate清空表的区别
delete
不影响自增列
truncate
自增列归零
修改
update `person` set `age` = 15 where `name` = '长江七号'查询
select `name` as 姓名,`age` as 年龄 from person as 人修改
-- 修改表名 ALTER TABLE person RENAME AS person1 -- 增加字段 ALTER TABLE person1 ADD age INT(11) -- 修改约束 ALTER TABLE person1 MODIFY age VARCHAR(11) -- 修改字段名 ALTER TABLE person1 CHANGE age age1 INT(1) -- 删除表的字段 ALTER TABLE person1 DROP age1删除
-- 删除表 DROP TABLE IF EXISTS person1所有的创建和删除加上判断是否存在,以免报错
INNODB 默认使用
MYISAM 早些年使用
MYISAMINNODB事务支持不支持支持数据行锁定不支持支持外键约束不支持支持全文索引支持不支持表空间大小小大,约为2倍安全性低高检索符合条件的值
select distinct `name` from person where `age` > 0 and `age` < 15 select distinct `name` from person where `age` between 0 and 15 select distinct `name` from person where not `age` = 15自连接
自己的表和自己的表连接,一张表拆为两张表
SELECT a.`categoryName` AS '父栏目',b.`categoryName` AS '子栏目' FROM `category` AS a,`category` AS b WHERE a.`categoryid` = b.`pid` SELECT a.`categoryName` AS '父栏目',b.`categoryName` AS '子栏目' FROM `category` AS a INNER JOIN `category` AS b ON a.`categoryid` = b.`pid`排序
升序 ASC
降序 DESC
select `name`,`age` from person where `age` > 0 order by `age` asc select `name`,`age` from person where `age` > 0 order by `age` desc分页
为什么分页?缓解数据库压力,用户体验更好语法: limit 起始值,条数第n页:limit (n-1)*pageSize,pageSize select `name`,`age` from person where `age` > 0 limit 0,5having用于分组过后过滤满足条件的组,通常和聚合函数一起出现
where用于分组前过滤数据,不能接聚合函数
按照效率排序:couunt(字段) < count(主键id) < count(1) <count(*)
select count(age) as '总和' from person select max(age) as '最大年龄' from person select min(age) as '最小年龄' from person select avg(age) as '平均' from personmd5加密不可逆,同一字符串加密结果一样。所以所谓破解,是将简单常用的收藏为字典,进行反向键值对(加密后-加密前)匹配
update testmd5 set pwd = MD5(pwd) insert into testmd5 values(4,'长江七号',md5('123456'))参考博客:https://blog.csdn.net/dengjili/article/details/82468576
事务原则:ACID原则 原子性,一致性,隔离性,持久性
原子性:针对同一个事务,要么都完成,要么都不完成
一致性:事务操作前后的数据完整性保持一致
持久性:事务提交了,持久化到数据库。事务一旦提交,则不可逆
隔离性:多个用户同时操作,排除其他事务对本事务的影响
隔离所导致的一些问题
脏读:指一个事务读取了另外一个事务未提交的数据。
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同。
虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。 (一般是行影响,多了一行)
MySQL事务隔离级别
读未提交(read-uncommitted) 不可重复读(read-committed) 可重复读(repeatable-read) 串行化(serializable)
执行事务
-- mysql默认开启事务自动提交 set autocommit = 0 -- 关闭 set autocommit = 1 -- 开启 -- 手动处理事务 set autocommit = 0 -- 关闭 -- 事务开启 start transaction -- 标记一个事务,这个开始的sql要么全成功,要么全失败 insert XXX insert XXX -- 提交 commit -- 回滚 回到原来的样子 rollback -- 事务结束 set autocommit = 1 -- 开启 /* 了解 */ savepoint 保存点名称 -- 设置一个事务的保存点 -- 回滚到保存点 rollback to savepoint 保存点名称 -- 删除保存点 release savepoint 保存点名称 -- 模拟转账 set autocommit = 0; start transaction update account set money = money - 500 where `name` = 'A' update account set money = money + 500 where `name` = 'B' commit; rollback; set autocommit = 1;建立索引的时机:
一般来说,在WHERE和JOIN中出现的列需要建立索引,但也不完全如此,因为MySQL的B-Tree只对<,<=,=,>,>=,BETWEEN,IN,以及不以通配符开始的LIKE才会使用索引。
数据量小时,区别不大。数据量大时,区别明显。可用explain查询select语句执行过程。空间换时间。
explain select * from person where `name` = 'zhangsan'索引的数据结构
本质:对mysql.user表增删改查
-- 创建用户 create USER 用户名 identified by '密码' create USER zmy identified by '123456' -- 修改指定用户密码 set password for zmy = PASSWORD('111111') -- 修改当前用户密码 set password = PASSWORD('111111') -- 重命名 rename USER zmy TO zmy2 -- 授予最高权限 (唯独不能给别人授权。(root能)) grant all privileges on *.* to zmy -- 查询指定用户权限 show grants for zmy -- 查询管理员权限 show grants for root@localhost -- 撤销权限 revoke all privileges on *.* from zmy -- 删除用户 drop user zmy糟糕的设计:
数据冗余,浪费空间数据插入和删除都会麻烦,异常(屏蔽使用物理外键)程序性能差第一范式
要求数据库表的每一列都是不可分割的原子数据项
学校信息家庭信息研究生,研一三口人,北京研究生,研一应该分为两列
三口人,北京应该分为两列
第二范式
前提:满足第一范式
每张表只描述一件事情,保证每一列都和主键有关
第三范式
前提:满足第一范式和第二范式
确保数据表中的每一列数据都和主键直接相关,而不能间接相关
学号姓名性别班主任姓名班主任性别201张三男陈六女202李四男孙七女203王五男周八女班主任性别直接依赖是班主任姓名,应该分成两张表:
学号姓名性别201张三男202李四男203王五男 班主任姓名班主任性别陈六女孙七女周八女Sun公司为了简化开发人员对数据库的操作,提供了一个java操作数据库的规范,俗称JDBC,不用的数据库由对应的厂商实现。
java.sqljavax.sqlmysql-connector-java-x.x.x.jar : 连接mysql 的驱动,由mysql的开发公司开发维护Java中JDBC的使用方法:
import java.sql.*; public class Test { public static void main(String[] args) throws ClassNotFoundException, SQLException { //加载驱动 Class.forName("com.mysql.jdbc.Driver"); //建立连接 获取数据库对象Connection String url = "jdbc:mysql://localhost:3306/school"; String userName = "root"; String password = "123456"; Connection c = DriverManager.getConnection(url,userName,password); //获取执行sql的对象 Statement state = c.createStatement(); String sql = "select * from `category`"; ResultSet rs = state.executeQuery(sql); //rs.beforeFirst();//移动到最前面 //rs.afterLast();//移动到最后面 //rs.next();//移动到下一个 //rs.previous()//移动到前一行 //rs.absolute(row);//移动到指定行 while(rs.next()) { System.out.println(rs.getObject("categoryName")); } //释放连接 rs.close(); state.close(); c.close(); } }封装后的版本
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 user = null; private static String password = null; private Connection conn = null; private Statement state = null; private ResultSet rs = null; static { try { InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"); Properties pt = new Properties(); pt.load(in); driver = pt.getProperty("driver"); url = pt.getProperty("url"); user = pt.getProperty("user"); password = pt.getProperty("password"); } catch (IOException e) { e.printStackTrace(); } //加载驱动 try { Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public ResultSet exeQuery(String sql) { try { conn = getConnection(); state = conn.createStatement(); rs = state.executeQuery(sql); } catch (SQLException e) { e.printStackTrace(); } return rs; } public int exeUpdate(String sql) { int row = 0; try { conn = getConnection(); state = conn.createStatement(); row = state.executeUpdate(sql); } catch (SQLException e) { e.printStackTrace(); } return row; } private static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,user,password); } public void release() { if(rs !=null) { try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(state!=null) { try { state.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //调用 JdbcUtils ju = new JdbcUtils(); String sql = "select * from `category`"; ResultSet rs = ju.exeQuery(sql); try { while(rs.next()) { System.out.println(rs.getObject("categoryName")); } } catch (SQLException e) { e.printStackTrace(); }finally{ ju.release(); }使用Statement , sql存在漏洞,通过拼接sql字符串
public void login(String username,String password) { JdbcUtils ju = new JdbcUtils(); String sql = "select * from users where name = '" + username + "' and password = '" + password + "'"; //拼接sql字符串存在sql注入问题,不安全 //当参数中的password传递为 " ' or 1 = 1 ",无视用户名密码就能查询到结果 ResultSet rs = ju.exeQuery(sql); try { while(rs.next()) { System.out.println(rs.getObject("XXX")); } } catch (SQLException e) { e.printStackTrace(); }finally{ ju.release(); } }使用PreparedStatement对象可以避免SQL注入(预编译sql、避免sql注入),并且效率更高。
import java.sql.*; public class JdbcUtils { public static void main(String[] args) throws ClassNotFoundException { //加载驱动 Class.forName("com.mysql.jdbc.Driver"); //建立连接 获取数据库对象Connection String url = "jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true"; String userName = "root"; String password = "123456"; Connection c = null; PreparedStatement state = null; ResultSet rs = null; try { c = DriverManager.getConnection(url,userName,password); //获取执行sql的对象 String sql = "select * from `app_user` where id = ?"; state = c.prepareStatement(sql);//预编译 检查 state.setInt(1, 56); rs = state.executeQuery();//不需要传递sql while(rs.next()) { System.out.println(rs.getObject("name")); } } catch (SQLException e) { e.printStackTrace(); }finally { //释放连接 try { if(rs != null) rs.close(); if(state != null) state.close(); if(c != null) c.close(); } catch (SQLException e) { e.printStackTrace(); } } } }连接释放很浪费资源,所以引入池。
开源数据源实现,实现DataSourace接口
知名的DataSource实现类:
DBCP
C3P0
Druid:阿里巴巴
DBCP
需要用到的jar包:
commons-dbcp-1.4、commons-pool-1.6
import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class Study01 { private static DataSource dataSource = null; private Connection conn = null; private Statement state = null; private ResultSet rs = null; static{ try{ InputStream in = Study01.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); Properties properties = new Properties(); properties.load(in); //创建数据源 dataSource = BasicDataSourceFactory.createDataSource(properties); }catch(Exception e){ e.printStackTrace(); } } public ResultSet exeQuery(String sql) { try { conn = getConnection(); state = conn.createStatement(); rs = state.executeQuery(sql); } catch (SQLException e) { e.printStackTrace(); } return rs; } public int exeUpdate(String sql) { int row = 0; try { conn = getConnection(); state = conn.createStatement(); row = state.executeUpdate(sql); } catch (SQLException e) { e.printStackTrace(); } return row; } private static Connection getConnection() throws SQLException { return dataSource.getConnection();//从数据源获取连接 } public void release() { if(rs !=null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(state!=null) { try { state.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } //调用 import java.sql.*; public class Test { public static void main(String[] args) { Study01 ju = new Study01(); String sql = "select * from `app_user`"; ResultSet rs = ju.exeQuery(sql); try { while(rs.next()) { System.out.println(rs.getObject("id")); } } catch (SQLException e) { e.printStackTrace(); }finally{ ju.release(); } } }dbcp配置文件dbcpconfig.properties
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbc 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=gbk #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTEDC3P0
需要的jar包
c3p0-0.9.5.5.jar、mchange-commons-java-0.2.19.jar
import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; //c3p0 public class Study02 { private static DataSource dataSource = null; private Connection conn = null; private Statement state = null; private ResultSet rs = null; static{ try{ //创建数据源 dataSource = new ComboPooledDataSource("Mysql"); }catch(Exception e){ e.printStackTrace(); } } public ResultSet exeQuery(String sql) { try { conn = getConnection(); state = conn.createStatement(); rs = state.executeQuery(sql); } catch (SQLException e) { e.printStackTrace(); } return rs; } public int exeUpdate(String sql) { int row = 0; try { conn = getConnection(); state = conn.createStatement(); row = state.executeUpdate(sql); } catch (SQLException e) { e.printStackTrace(); } return row; } private static Connection getConnection() throws SQLException { return dataSource.getConnection();//从数据源获取连接 } public void release() { if(rs !=null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(state!=null) { try { state.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } //调用 import java.sql.*; public class Test { public static void main(String[] args) { Study02 ju = new Study02(); String sql = "select * from `app_user`"; ResultSet rs = ju.exeQuery(sql); try { while(rs.next()) { System.out.println(rs.getObject("id")); } } catch (SQLException e) { e.printStackTrace(); }finally{ ju.release(); } } }c3p0-config.xml配置文件内容
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/school</property> <property name="user">root</property> <property name="password">123456</property> </default-config> <!-- This app is massive! --> <named-config name="Mysql"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/school</property> <property name="user">root</property> <property name="password">123456</property> </named-config> </c3p0-config>