《带你走进Java的世界》第五章相关学习笔记
对于高级程序员,在SQL方面不仅要会简单的CURD语句,还得会使用相对复杂的语句实现项目的各种需求,了解诸如批处理和事务等高级知识点。更重要的是,还得具备一定的数据库调优能力。
项目中常用SQL语句注意点
尽量别写select *
不仅可能出现生产问题(插入新字段后结果错误),还会造成性能问题。
count(*)和count(字段名)比较
- 如果表中某字段允许为空,可能得到错误的结果
- 推荐使用count(主键)方式,有索引,性能会高些
- 经常见到select count(1) from xxx写法,标识用第一个字段获取总条数
但不推荐使用,万一第一个字段允许为空或者哪天在id前又加了允许为空的新字段。
insert 注意点
插入时要加入字段列表
一些情况下能同时插入多条
insert into student (id,name,address) values (‘1’,’Peter’,’China’),(‘2’,’Mike’,’US’)
能够提升插入的性能,但需要注意:
- 有的数据库不支持批量插入,不如Oracle
- 在一个insert里,不能无限多插入,否则会出错
delete里,可以通过in语句删除多条
delete from student where id in (1,2,3,xxx)
能够提升性能,同样不能在一句delete语句的in从句里待删太多条,否则会出错
merge和update比较
merge——无则插入有则更新
注意点:
不是每种数据库都支持Merge,Oracle、SQL Server可用,MySQL不可用
存储过程分析
会编写存储过程是一项比较重要的技能,有几项开发要点:
争议点。存储过程只在创建时进行编译,以后每次执行都不需重新编译,这样能提高数据库执行速度。
- 针对某个业务逻辑,需要对多个表进行多次insert/delete/update/select操作,可以把这些操作汇集成一个存储过程,提高代码的重用性。
- 存储过程移植性很差
- 存储过程很难调试,Java抛出的异常只能知道“哪个存储过程出错”
⭐面试说辞*:
- 知道存储过程的语法,不仅学过,也在项目里用过
- 因为存储过程不大好调试,所以项目里用存储过程实现的功能比较简单,然后讲个存储过程实现的具体业务。
- 项目里有大批量数据插入更新操作时,用存储过程和JDBC里的批处理做了对比测试,具体做法是插入1w条数据,发现批处理的性能要比存储过程的好,所以项目里没有用存储过程来处理大批量的insert/delete/update操作。
数据库操作面试题
- 事务的四大特性是什么?
- 共享锁和排斥锁的含义及用途?
- 乐观锁和悲观锁的含义及用途?
- 内连接、外连接、全连接和左连接的语法及用途
- 触发器、视图和游标的含义及用途
- 三范式的含义及反范式的含义,在建表时用哪种?
- 什么是SQL注入?后果?预防?
传统JDBC
JDBC全称Java Database Connectivity,是Java语言用来规范客户端程序如何访问数据库的应用程序接口。
通过JDBC开发读写数据库
首先引入mysql-connector-java-xxx-bin.jar这个MySQL驱动包
然后,传统JDBC六步骤:
- 加载驱动程序;
- 获得数据库连接;
- 创建一个Statement对象;
- 操作数据库,实现增删改查;
- 获取结果集;
- 关闭资源。
ORM
全称Object Relation Mapping,对象-映射-关系型数据库。用于实现面向对象编程语言里不同类型系统的数据之间的转换。提供了实现持久化层的另一种模式。
目前最流行的是:Mybatis和Spring Data JPA
⭐优化数据库部分
这部分大段内容使用的是传统的JDBC,之后找资料补充:配置文件,批处理,防SQL注入
掘金·性能优化之MySQL优化
掘金·MySQL优化面试
⭐事务操作
ACID
原子性(Atomicity):要么同时成功,要么同时失败,底层依赖undo log
实现(回滚恢复)。
隔离性(Isolation):事务并发执行时,内部操作不能互相干扰,否则会产生下面第三点的常见问题。
持久性(Durability):一旦提交了事务,就将数据持久化到硬盘。持久性由redo log
日志保证,当要修改数据时,MySQL首先把这条记录所在页找到,然后把该页加载到内存中,将对应记录修改。为了防止内存修改完MySQL就挂了,MySQL此时还会写一份redo log
,记载这次在某个页做了什么修改。
一致性(Consistency):前三者均是为了保障数据一致性的手段。
开启事务,合理地提交和回滚
事务常见问题:脏读、不可重复读和幻读
友情链接:一文详解脏读、不可重复读、幻读
- 脏读:一个事务读取了另一个事务尚未提交的数据
- 不可重复读:一个事务的操作导致另一个事务前后两次读取到不同的数据
- 幻读:一个事务的操作导致另一个事务前后两次查询结果不同
幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select
操作得到的结果所表征的数据状态无法支撑后续的业务操作。
更为具体一些:select
某记录是否存在,不存在,准备插入此记录,但执行 insert
时发现此记录已存在,无法插入,此时就发生了幻读。
不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。
事务隔离级别
通过事务隔离级别解决上面的读写不一致问题,在InnoDB引擎中,定义了四种隔离级别:
首先说读未提交,它是性能最好,也可以说它是最野蛮的方式,因为它压根儿就不加锁,所以根本谈不上什么隔离效果,可以理解为没有隔离。
再来说串行化。串行化就相当于上面所说的,处理一个人请求的时候,别的人都等着。读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。
最后说读提交和可重复读。这两种隔离级别是比较复杂的,既要允许一定的并发,又想要兼顾的解决问题。MySQL默认事务隔离级别为可重复读(RR),oracle默认事务隔离级别为读已提交(RC),
数据库的事务隔离越严格,并发副作用越小,但付出的代价越大;因为事务隔离本质就是使事务在一定程度上处于串行状态,这本身就是和并发相矛盾的。
同时,不同的应用对读一致性和事务隔离级别是不一样的,比如许多应用对数据的一致性没那么个高要求,相反,对并发有一定要求。
后续知识(解决可重复读幻读问题):隔离级别、幻读、Gap Lock、Next-Key Lock
不同的隔离级别对事务间的隔离性不一样,而隔离性是由MySQL的各种锁来实现的,只是它屏蔽了加锁的细节。