既然${}会引起sql注入,为什么有了#{}还需要有${}呢?那其存在的意义是什么?
#{}
主要用于预编译,而预编译的场景其实非常受限,而${}用于替换,很多场景会出现替换,而这种场景可不是预编译
数据库的访问底层是通过tcp实现的,当链接中断是程序是无法得知,导致程序一直会停顿一段时间在这,最终会导致用户体验不好,因此面对数据库连接中断的异常,该怎么设置mybatis呢?
connection操作底层是一个循环处理操作,因此可以进行时间有关的参数:
数据库服务器活的杠杠的,但是因为网络用塞,客户端仍然连不上服务器端,这个时候就要设置timeout,别一直傻等着
插入的过程一般都是分两步的:先判断是否存在记录,没有存在则插入否则不插入。如果存在并发操作,那么同时进行了第一步,然后大家都发现没有记录,然后都插入了数据从而造成数据的重复
解决插入重复的思路 :
总结:多线程同时插入数据,谁获取锁并插入数据成功了其他线程不做任何操作。当插入数据失败后,其他线程抢锁进行插入数据。
数据库插入百万级数据的时候,还没操作完,但是把服务器重启了,数据库会继续执行吗? 还是直接回滚了?
不会自动继续执行,不会自动直接回滚 ,但可以依据事务日志进行回滚或者进行执行。
事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化 ,两种类型:
在事务执行的过程中,除了记录redo log,还会记录一定量的undo log。
Java客户端中的一个Connection不是在MySQL中就对应一个线程来处理这个链接,而是:
监听socket的主线程+线程池里面固定数目的工作线程来处理的
高性能服务器端端开发底层主要靠I/O复用来处理,这种模式:
单线程+事件处理机制
在MySQL有一个主线程,这是单线程(与Java中处处强调多线程的思想有点不同哦),它不断的循环查看是否有socket是否有读写事件,如果有读写事件,再从线程池里面找个工作线程处理这个socket的读写事件,完事之后工作线程会回到线程池。
解析XML: 初始化SqlSessionFactoryBean会将mapperLocations路径下所有的XML文件进行解析
Dao接口代理: Spring中的FactoryBean 和 JDK动态代理返回了可以注入的一个Dao接口的代理对象
执行: 通过statement全限定类型+方法名拿到MappedStatement 对象,然后通过执行器Executor去执行具体SQL并返回
通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致
通过<resultMap>来映射字段名和实体类属性名的一一对应的关系。
在Java代码中添加sql通配符
string name = "%Ccww%"; list<name> names = mapper.selectName(name);
<select id="selectName"> select * from users where name like #{value} </select>
在sql语句中拼接通配符,会引起sql注入
<select id="selectName"> select * from users where name like "%"#{value}"%" </select>
接口绑定 : 在MyBatis中任意定义接口,然后把接口里边的方法和SQL语句绑定,我们可以直接调用接口方法,比起SqlSession提供的方法我们可以有更加灵活的选择和设置
接口绑定有两种实现方式 :
11. 通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
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就会导致覆盖了。
Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非数据库分页。
在实际场景下,使用如下两种方案:
这两者都是基于数据库分页,差别在于前者是工程师手动编写分页条件,后者是插件自动添加分页条件。
分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义分页插件。在插件的拦截方法内,拦截待执行的 SQL ,然后重写 SQL ,根据dialect 方言,添加对应的物理分页语句和物理分页参数。
举例: SELECT * FROM student
,拦截 SQL 后重写为: select * FROM student LIMI 0,10
。
目前市面上目前使用比较广泛的 MyBatis 分页插件有:
Mybatis 动态 SQL ,可以让我们在 XML 映射文件内,以 XML 标签的形式编写动态 SQL ,完成逻辑判断和动态拼接 SQL 的功能。
Mybatis 提供了 9 种动态 SQL 标签:
其执行原理为,使用 OGNL 的表达式,从 SQL 参数对象中计算表达式的值,根据表达式的值动态拼接 SQL ,以此来完成动态 SQL 的功能
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。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内
在Mybatis配置文件中,可以指定默认的ExecutorType执行器类型,也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型参数。