欢迎关注文章系列,一块儿学习 《提高能力,涨薪可待篇》
《面试知识,工做可待篇》
《实战演练,拒绝996篇》
也欢迎关注微信公众号【Ccww笔记】,原创技术文章第一时间推出
若是此文对你有帮助、喜欢的话,那就点个赞呗,点个关注呗!html
往期文章系列:java
mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值。git
mybatis在处理${}时,就是把${}替换成变量的值。程序员
使用#{}能够有效的防止SQL注入,提升系统安全性。缘由在于:预编译机制。预编译完成以后,SQL的结构已经固定,即使用户输入非法参数,也不会对SQL的结构产生影响,从而避免了潜在的安全风险。github
预编译是提早对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。咱们知道,SQL注入是发生在编译的过程当中,由于恶意注入了某些特殊字符,最后被编译成了恶意的执行操做。而预编译机制则能够很好的防止SQL注入。面试
既然${}会引发sql注入,为何有了#{}还须要有${}呢?那其存在的意义是什么?redis
#{}主要用于预编译,而预编译的场景其实很是受限,而${}用于替换,不少场景会出现替换,而这种场景可不是预编译sql
数据库的访问底层是经过tcp实现的,当连接中断是程序是没法得知,致使程序一直会停顿一段时间在这,最终会致使用户体验很差,所以面对数据库链接中断的异常,该怎么设置mybatis呢?数据库
connection操做底层是一个循环处理操做,所以能够进行时间有关的参数:缓存
数据库服务器活的杠杠的,可是由于网络用塞,客户端仍然连不上服务器端,这个时候就要设置timeout,别一直傻等着
插入的过程通常都是分两步的:先判断是否存在记录,没有存在则插入不然不插入。若是存在并发操做,那么同时进行了第一步,而后你们都发现没有记录,而后都插入了数据从而形成数据的重复
解决插入重复的思路 :
总结:多线程同时插入数据,谁获取锁并插入数据成功了其余线程不作任何操做。当插入数据失败后,其余线程抢锁进行插入数据。
数据库插入百万级数据的时候,还没操做完,可是把服务器重启了,数据库会继续执行吗? 仍是直接回滚了?
不会自动继续执行,不会自动直接回滚 ,但能够依据事务日志进行回滚或者进行执行。
事务开启时,事务中的操做,都会先写入存储引擎的日志缓冲中,在事务提交以前,这些缓冲的日志都须要提早刷新到磁盘上持久化 ,两种类型:
在事务执行的过程当中,除了记录redo log,还会记录必定量的undo log。
Java客户端中的一个Connection不是在MySQL中就对应一个线程来处理这个连接,而是:
监听socket的主线程+线程池里面固定数目的工做线程来处理的
高性能服务器端端开发底层主要靠I/O复用来处理,这种模式:
单线程+事件处理机制
在MySQL有一个主线程,这是单线程(与Java中到处强调多线程的思想有点不一样哦),它不断的循环查看是否有socket是否有读写事件,若是有读写事件,再从线程池里面找个工做线程处理这个socket的读写事件,完事以后工做线程会回到线程池。
string name = "%Ccww%";
list<name> names = mapper.selectName(name);
复制代码
<select id="selectName">
select * from users where name like #{value}
</select>
复制代码
<select id="selectName">
select * from users where name like "%"#{value}"%"
</select>
复制代码
接口绑定 : 在MyBatis中任意定义接口,而后把接口里边的方法和SQL语句绑定,咱们能够直接调用接口方法,比起SqlSession提供的方法咱们能够有更加灵活的选择和设置
接口绑定有两种实现方式 :
Dao接口为Mapper接口。
接口的全限名为映射文件中的namespace的值;
接口的方法名为映射文件中Mapper的Statement的id值;
接口方法内的参数为传递给sql的参数。
Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串做为key值,可惟必定位一个MapperStatement。在Mybatis中,每个 <select>、<insert>、<update>、<delete>标签,都会被解析为一个MapperStatement对象
Mapper接口里的方法,是不能重载的,由于是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工做原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所表明的sql,而后将sql执行结果返回。
基于上面,能够得知
Statement=namespace+id
若是配置了namespace能够重复的 ,但若是没有配置namespace的话,那么相同的id就会致使覆盖了。
(1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储做用域为 Session,当 Session flush 或 close 以后,该 Session 中的全部 Cache 就将清空,默认打开一级缓存。
(2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不一样在于其存储做用域为 Mapper(Namespace),而且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类须要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;
(3)对于缓存数据更新机制,当某一个做用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操做后,默认该做用域下全部 select 中的缓存将被 clear。
Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非数据库分页。
在实际场景下,使用以下两种方案:
这二者都是基于数据库分页,差异在于前者是工程师手动编写分页条件,后者是插件自动添加分页条件。
分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义分页插件。在插件的拦截方法内,拦截待执行的 SQL ,而后重写 SQL ,根据dialect 方言,添加对应的物理分页语句和物理分页参数。
举例:SELECT * FROM student
,拦截 SQL 后重写为:select * FROM student LIMI 0,10
。
目前市面上目前使用比较普遍的 MyBatis 分页插件有:
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。
在Mybatis配置文件中,能够配置是否启用延迟加载:
lazyLoadingEnabled=true|false。
原理是,使用CGLIB建立目标对象的代理对象,当调用目标方法时,进入拦截器方法.
好比调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,而后调用a.setB(b),因而a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
固然了,不光是Mybatis,几乎全部的包括Hibernate,支持延迟加载的原理都是同样的。
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
**SimpleExecutor:**每执行一次update或select,就开启一个Statement对象,用完马上关闭Statement对象。
**ReuseExecutor:**执行update或select,以sql做为key查找Statement对象,存在就使用,不存在就建立,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。简言之,就是重复使用Statement对象。
**BatchExecutor:**执行update(没有select,JDBC批处理不支持select),将全部sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每一个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
做用范围:Executor的这些特色,都严格限制在SqlSession生命周期范围内
在Mybatis配置文件中,能够指定默认的ExecutorType执行器类型,也能够手动给DefaultSqlSessionFactory的建立SqlSession的方法传递ExecutorType类型参数。
总结:
参考文章:
也欢迎关注微信公众号【Ccww笔记】,原创技术文章第一时间推出
若是此文对你有帮助、喜欢的话,那就点个赞呗,点个关注呗!![]()