1)MyBatis 把 sql 语句从 Java 源程序中独立出来,放在单独的 XML 文件中编写, 给程序的维护带来了很大便利。(维护)
2)MyBatis 封装了底层 JDBC API 的调用细节,并能自动将结果集转换成 Java Bean 对象,大大简化了 Java 数据库编程的重复工作。 (简化)
3)因为 MyBatis 需要程序员自己去编写 sql 语句,程序员可以结合数据库自身的 特点灵活控制 sql 语句,因此能够实现比 Hibernate 等全自动 orm 框架更高的查 询效率,能够完成复杂查询。(灵活)
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集 合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询 关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映 射工具。
接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上 @Select@Update 等注解里面包含 Sql 语句来绑定,另外一种就是通过 xml 里面写 SQL 来绑定,在这种情况下,要指定 xml 映射文件里面的 namespace 必须为接口的全 路径名。
resultType 和 resultMap 都是表示数据库表与 pojo 之间的映射规则的。类的名字和数据 库相同时,可以直接设置 resultType 参数为 Pojo 类。若不同或者有关联查询,需要设置 resultMap 将结果名字和 Pojo 名字进行转换;从编程的最佳实践来讲,强制使用resultMap, 不要用 resultClass 当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义; 见《Java 开发手册 1.5》之 5.4.3;
建议不要用 Map 作为 mapper 的输入和输出,不利于代码的可读性和可维护性;见《Java 开发手册 1.5》之 5.4.6;
向 sql 语句中传递的可变参数,分为预编译#{}和传值${}两种
而且这两种方式都能返回数据库主键字段;
嵌套查询会导致“N+1 查询问题”,导致该问题产生的原因:
这个问题会导致成百上千的 SQL 语句被执行。这通常不是期望的。 解决“N+1 查询问题”的办法就是开启懒加载、按需加载数据,开启懒加载配置: 在节点上配置“fetchType=lazy”,在 MyBatis 核心配置文件中加入如下配置:
<setting name="aggressiveLazyLoading" value="false" />
一级缓存存在于 SqlSession 的生命周期中,在同一个 SqlSession 中查询时使用。二级缓存 也叫应用缓存,存在于 SqlSessionFactory 的生命周期中,可以理解为跨 sqlSession;二级缓存是 以 namespace 为单位的,不同 namespace 下的操作互不影响。在项目中为了避免脏读的问题, 建议不适用二级缓存。
1)Mybatis 使用 RowBounds 对象进行分页,也可以直接编写 sql 实现分页,也可以使用Mybatis 的分页插件。
2)分页插件的原理:实现 Mybatis 提供的接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql。
举例:select * from student,拦截 sql 后重写为:
select t. from (select * from student)t limit 0,10*
1)Mybatis 仅可以编写针对 ParameterHandler、ResultSetHandler、StatementHandler、Executor 这 4 种接口的插件,Mybatis 通过动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler 的 invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
2)实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
看情况
不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;
如果没有配置 namespace, 那么 id 不能重复;
毕竟 namespace 不是必须的,只是最佳实践而已。原因就是 namespace+id 是作为 Map的 key 使用的,如果没有 namespace,就剩下 id, 那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同, namespace+id 自然也就不同
Mybatis 有三种基本的 Executor 执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
1) SimpleExecutor:Mybatis 的默认执行器,每执行一次 update 或 select,就开启一个 Statement 对 象,用完立刻关闭 Statement 对象。
2)ReuseExecutor:执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放 置于 Map
3)BatchExecutor:完成批处理。
表面上我们在使用 mapper 接口访问数据库,实际 MyBatis 通过动态代理生成了 mapper 接 口的实现类,通过这个动态生成的实现类,将数据库的访问请求转发给 SqlSession。转发过程中 需要实现三个翻译:
请求转发给 SqlSession 后实现对数据库的访问操作
属性 | 描述 |
---|---|
useGeneratedKeys | (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系 数据库管理系统的自动递增字段),默认值:false。 |
keyProperty | ( 仅 对 insert 和 update 有 用 ) 唯 一 标 记 一 个 属 性 , MyBatis 会 通 过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键 值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
<insert id="insert1" parameterType="TUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (id, userName, realName,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{position.id,jdbcType=INTEGER})
insert>
属性 | 描述 |
---|---|
keyProperty | selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号 分隔的属性名称列表 |
resultType | 结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。 MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的 列,则可以使用一个包含期望属性的 Object |
order(对插入而言) | 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设 置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后获 取主键字段;mysql 数据库自增长的方式 order 设置为 After,oracle 数据库通过 sequnce 获取主键 order |
oracle
<selectKey keyProperty=“id” order= "Before" resultType="int">
select SEQ_ID.nextval from dual
selectKey>
mysql
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
selectKey>
foreach,if元素
where, trim,set元素
使用where 1 = 1 and, 不优雅
使用where子元素处理, 比较优雅, 没有条件时候就没有where字句
动态sql的set元素
trim元素是其他set,where的抽象
单条执行一个sql: 数组使用 collection = “array”, 集合的collection=“list”,
批量执行多条sql: 批量操作, 指定执行器的操作类型的batch, 不使用batch方式就会使用多个连接去执行, 生成多个事务, 所以使用batch就会使用同一个事务, 需要自己提交
generatorConfig.xml
DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
<properties resource="db.properties" />
<classPathEntry location="${class_path}" />
<context id="context1" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true" />
commentGenerator>
<jdbcConnection driverClass="${jdbc_driver}"
connectionURL="${jdbc_url}" userId="${jdbc_username}" password="${jdbc_password}" />
<javaModelGenerator targetPackage="com.enjoylearning.mybatis.entity"
targetProject="${project_src}" />
<sqlMapGenerator targetPackage="." targetProject="${project_mapper_xml}" />
<javaClientGenerator targetPackage="com.enjoylearning.mybatis.mapper"
targetProject="${project_src}" type="XMLMAPPER" />
<table schema="${jdbc_username}" tableName="t_role"
enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" selectByExampleQueryId="false">
table>
context>
generatorConfiguration>
三种运行方式
mvn mybatis-generator.generate
使用main运行
使用java -jar 运行
java -jar mybatis-generator-core-xxx.jar -configgile generatorConfig.xml
连接池数据结构和核心算法
重点理解学习
使用了SynchronizedCache装饰器, 装饰器的所有的方法都加了synchronized关键字, 实现了同步操作