Mybatis概览
- 此文章仅个人笔记,非知识点博客文章
- 对原生态JDBC程序的封装
- mybatis开发DAO的方法(两种):
- 原始DAO方法(程序需要编写DAO接口与实现类)
- mybatis的mapper接口(相当于DAO接口)代理开发
- mybatsi的核心:
- mybatis输入映射
- mybatis输出映射
- mybatis的动态SQL
- mybatis延迟加载
- mybatis高级结果集映射
- 包含一个全局的配置文件与映射关系文件,如:mybatis.xml(全局配置文件), mapper.xml(映射文件)
Mybatis框架
- mybatis为apache下的一个持久层框架,mybatis开发更多的是专注于SQL,开发自由灵活
- mybatsi可以向preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成Java对象(输出映射)
- 通过SqlSessionFactory创建SqlSession, 通过sqlSession的Executor(分两种:基本的与缓存的)去操作(CRUD)数据库
Mybatis入门
开发环境:
- mybatis的jar包
log4j.properties(用于查看日志),可从mabatis的配置文件中找到,开发环境设置为debug级别,上线环境设置为info级别,如:
log4j.rootLogger=DEBUG, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
全局配置文件mybatis.xml:
<configuration> <!-- 与Spring整合后environment配置将移除 --> <environments> <environment id="development"> <!-- 使用jdbc事物管理,事物控制由mybatis --> <transactionManager type="JDBC" /> <!-- 数据库连接池, 由mybatis管理 --> <dataSource type="POOLED"> <prioperty name="driver" value="..." /> <prioperty name="url" value="..." /> <prioperty name="username" value="..." /> <prioperty name="password" value="..." /> <!-- ... --> </dataSource> </environment> </environments> <!-- 配置映射文件 --> <mappers> <mapper resource="sqlMapper/User.xml" /> </mappers> </configuration>
映射文件User.xml:
<mapper namesapce="user"> <!-- 在映射文件中可以配置多个SQL语句对应不同的数据库操作 --> <!-- finUserById: 为statement的id parameterType:指定输入参数的类型 resultType:指定输出的结果集映射的Java对象类型 #{id}: 其中的id表示接收输入的参数,参数名称就是id,如果输入参数是简单类型,#{}中的参数可以任意,可以其他任何名称 模糊查询使用$符(不建议使用),注意易引起SQL注入,切传入的名称只能是value,如下 --> <select id="findUserById" parameterType="int" resultType="com.demo.User"> select * from user where id=#{id} </select> <select id="findUserByName" parameterType="int" resultType="com.demo.User"> select * from user where username like '%${value}%' </select> </mapper>
mysql获取插入的自增id值,使用last_insert_id()方法,如:
select last_inser_id()
映射的SQL如下:
<insert id="inserUser" parameterType="com.demo.User"> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select last_insert_id() </selectKey> insert into user value(#{username}, #{birthday}, #{sex}, #{address}) </user>
- Mybatis与Hibernate的本质区别与应用场景:
- Hibernate:标准ORM框架,sql语句自动生成,对SQL语句进行优化困难,适用于需求变化不多的中小型项目,如后台管理系统:erp,、orm、oa
- Mybatis:专注于SQL本身,需要编写SQL,sql的修改优化方便,不完全的ORM框架,适用于需求变化较多的项目,如互联网项目
Mybatis开发DAO的方法
- SqlSessionFactoryBuild创建SqlSessionFactory
- SqlSessionFactory创建SqlSession,SqlSessionFactory可以单例创建
- SqlSession是非线程安全的,SqlSession的最佳应用场合是在方法体内,即定义为局部变量
- DAO开发:
- 原始方法DAO开发:
- 编写DAO接口
- 编写DAO接口实现类
- mapper代理方法开发DAO:
- 只需要编写DAO接口,即mapper接口
- 编写对应的mapper.xml映射文件
- Mybatis可以自动生成mapper接口实现类的代理对象
- mapper接口开发规范:
- 在mapper.xml中namespace属性值等于mapper接口地址,如:com.demo.mapper.UserMapper
- mapper.xml中的statement的id需要与mapper接口类的方法名相同
- mapper.xml中的statement的parameterType指定的类型需要与mapper接口类中的方法输入参数类型一致
- mapper.xml中的statement的resultType指定的类型需要与mapper接口类中的方法返回值类型一致
- 通过使用SqlSession的getMapper方法获取mapper接口代理对象
- 原始方法DAO开发:
Mybatis全局配置文件mybatis.xml:
- properties(属性):如数据库的链接信息
- settings(全局配置参数):如开启二级缓存、延迟加载等
typeAliases(类型别名):可以用于定义POJO的别名,如:
<!-- 单个别名定义 --> <typeAlias alias="user" type="com.demo.User" /> <!-- 批量定义别名,别名就是类名首字母小写 --> <package name="com.demo" />
- typeHandlers(类型处理器):完成JDBC与Java类型的转换
- objectFactory(对象工厂):
mappers(映射器):加载映射文件,通过resource属性加载单个映射文件
使用相对于类路径的资源:
<mapper resource="sqlMap/User.xml" />
使用完全限定路径:
<mapper url="file:///D:workspace_20170712\mybatis\sqlMap\User.xml" />
使用mapper接口类路径(要求mapper接口名称与mapper映射文件名称一致且在同一目录下):
<mapper class="com.demo.mapper.UserMapper" />
批量加载资源(要求与使用mapper接口类路径一致):
<package name="com.demo" />
- 输出映射(resultType):
- 只有查询的列名或别名与POJO的属性名一致时才能创建成功
使用resultMap完成高级映射:
- 如果查询出来的列名与POJO的属性名不一致,通过定义一个resultMap对列名和POJO属性名之间做一个映射关系
定义resultMap,使用resultMap作为statement的输出映射类型
<!-- type:resultMap最终映射的Java对象类型,可以使用别名 id:对resultMap的唯一标识 --> <resultMap type="com.demo.User" id="userResultMap"> <!-- id表示查询结果集中唯一标识, column:查询出来的列名 property:type指定的POJO的属性名 result表示查询结果集中普通标识 --> <id column="" property="" /> <result column="" property="" /> </resultMap>
动态SQL
在sql中使用where, if标签,如:
<select id="findUserCount" parameterType="com.demo.User" resultType="int"> select count(*) from user <where> <if test="username!=null"> and user.username="${username}" </if> //... </where> </select>
Sql片段(提高重用性):
- 不要在sql片段中使用where标签
- 在SQL中使用where的子标签include来引用sql片段
如:
<sql id="query_user_where"> <if test="username!=null"> and user.username="${username}" </if> //... </sql> <select id="findUserCount" parameterType="com.demo.User" resultType="int"> select count(*) from user <where> <include refid="query_user_where" /> </where> </select>
高级映射
- 将关联查询的列映射到一个POJO属性中(一对一)
- 将关联查询的列映射到一个List中(一对多)
关联查询的resultMap:
查询到单一记录时,使用association标签,如:
JavaBean:
public class Order{ private int id; private String orderName; private User user; private List<OrderDetail> orderDetails; //.... } public class User{ private int id; private String userName; private String sex; //... }
resultMap:
<resultMap type="com.demo.Order" id="orderWithUser"> <id column="order_id" property="id" /> <result column="order_name" property="orderName" /> <!-- 关联查询的user --> <association property="user" javaType="com.demo.User" > <id column="user_id" property="id"/> <result column="user_name" property="userName"/> </association> </resultMap>
查询到多条记录时使用collection标签,如:
<resultMap type="com.demo.Order" id="orderWithUser" extends="orderWithUser"> <!-- 使用了extends,所示可以省略当前的order属性映射 --> <id column="order_id" property="id" /> <result column="order_name" property="orderName" /> <collection property="orderDetails" ofType="com.demo.OrderDetail"> <id column="" property="" /> <result column="" property="" /> </collection> </resultMap>
- resultType与resultMap的比较:
- resultType使用更加方便
- resultMap可以实现延迟加载,而resultType则不行
延迟加载
- association与collection具有延迟加载的功能
- association使用select属性指定延迟加载的statement的id,使用column属性指定关联查询的列名
mybatis需要开启延迟加载,默认是未开启,如下方式在全局配置文件中开启懒加载:
<settings> <setting name="lazyLoadingEnabled" value="true" /> <setting name="aggressiveLazyLoading" value="false" /> <settings>
查询缓存
- 一级缓存 - SqlSession级别的缓存
- 在SqlSeesion对象中有一个数据结构(HashMap)用于存储缓存数据,不同的SqlSession之间的缓存区域互不影响
- SqlSession执行commit操作(insert、update、delete)后,会清空SqlSession中的一级缓存
- mybatis默认支持一级缓存
二级缓存 - Mapper级别的缓存
- 多个SqlSession去操作同一个Mapper的SQL语句,二级缓存是跨SqlSession的
- mybatis的二级缓存需要手动开启
- 二级缓存的缓存区域是按照namespace区分的,即每一个namespace的mapper都存在一个二级缓存区域
二级缓存的开启需要在全局配置文件中配置,同时也需要在需要开启的mapper的配置文件中设置
在全局文件的配置如下:
<setting name="cacheEnabled" value="true" />
在Mapper配置文件中的配置如下:
<!-- 其中的type属性可以设置自定义的Cache实现类或第三方框架的Cache实现类 --> <cache />
- 对应的POJO类应该实现序列化接口,以便将缓存数据取出并实现反序列化操作,因为二级缓存的数据存储介质不一定在内存中
- SqlSession执行close操作之后才能将数据保存到二级缓存
使用useCache属性可以禁用二级缓存,使用flushCache可以刷新(清空)二级缓存,默认值均为true,如:
<select id="findUserById" resultType="com.demo.User" useCache="false"> //sql... </select>
- ehcache、redis、memcached是一个分布式的缓存框架
- mybatis提供了一个cache接口,实现自定义的缓存机制,Mybatis默认实现的Cache类为PrepetualCache,开发自定义的缓存逻辑时可以参考默认的Cache类实现
使用ehcache框架时,需要配置相应的ehcache文件:
一级缓存是针对一个SqlSession,而二级缓存是针对多个SqlSession的
Mybatis整合Spring
Mybatis与Spring整合 - sqlSessionFactory配置
- 持久层的mapper都需要spring管理,需要spring通过单例方式管理sqlSessionFactory
- 整合环境(jar包):
- mybatis
- spring
- mybatis与spring的整合包(mybatis-spring.jar)
在spring的配置文件(applicationContext.xml)中配置sqlSessionFactory
<!-- 加载配置文件 --> <context:property-placeholder location="classpath:db.property" /> <!-- 数据库连接池 --> <bean id="dataSource" class=""> <property name="" value="" /> <!-- 数据源的信息 --> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="mybatis.xml" /> <!-- dataSource --> <property name="dataSource" ref="dataSource" /> </bean>
mybatis与spring整合后的原始DAO开发:
- 创建mapper.xml映射文件与DAO接口及其实现类
- 在全局文件中通过mappers元素加载映射文件
在创建DAO实现类时,使其继承SqlSessionDaoSupport类,使得不用在实现类类中显示的声明SqlSessionFactory属性,在DAO方法中使用this.getSqlSession()获取SqlSession,如下:
public class UserDAOImpl extends SqlSessionDaoSupport implements UserDAO{ public User findUserById(int id){ SqlSession sqlSession = this.getSqlSession(); //操作数据库,方法结束自动关闭sqlSession,不需要显示close return user; } } 在spring配置文件中配置DAO: <bean id="userDAO" class="com.demo.mm.dao.UserDAOImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
mybatis与spring整合后的mapper代理开发:
- 创建Mapper接口类及其mapper.xml文件
在spring的配置文件中配置mapper,通过MapperFactoryBean创建代理对象:
<!-- MapperFactoryBean根据mapper接口生成代理对象 --> <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <!-- 指定mapper接口, mapperInterface为MapperFactoryBean的属性名 --> <property name="mapperInterface" value="com.demo.mm.mapper.UserMapper" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
mapper的批量配置,从mapper包中扫描mapper接口,自动创建代理对象并且在spring容器中注册(建议使用):
<!-- 在spring中加入mapper扫描后,在mybatis的配置文件中就不需要再加入扫描mapper --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 1.指定扫描的包名,basePackage为MapperScannerConfigurer类中的属性名 2.mapper.java与mapper.xml的文件名需要保持一致,且在同一目录中 3.如果扫描多个包不能使用通配符,只能使用逗号分隔 --> <property name="basePackage" value="com.demo.mm.mapper" /> <!-- 此处不能使用sqlSessionFactory --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean>
逆向工程
- mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码,如下:
- mapper.java
- mapper.xml
- POJO类
- 在实际开发中,常用的逆向工程方式为由数据库的表生成java代码
- 下载mybatis逆向工程:
- mybatis-generator-core-(version)-bundle
- 逆向工程的使用:
- 使用Java程序与XML配置文件的方式
- 具体配置参考官方文档