Mybatis内容记录

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis内容记录相关的知识,希望对你有一定的参考价值。

 

 

 

 

MyBatis

  MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
  MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

? Mybatis架构

 

技术分享图片

? mybatis配置
  SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
  mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
? 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
? 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
? mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
? Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。

  mapper.xml文件中一个sql对应一个MappedStatement对象,sql的id即是Mappedstatement的id。

? MappedStatement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
? MappedStatement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

 

mybatis默认使用log4j作为输出日志信息

 

技术分享图片
1 # Global logging configuration
2 log4j.rootLogger=DEBUG, stdout
3 # Console output...
4 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
log4j.properties

 

? #{}和${}
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。


? parameterType和resultType
  parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
  resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中

? selectOne和selectList
  selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:org.apache.ibatis.exceptions.TooManyResultsException

  selectList可以查询一条或多条记录。

? namespace
  mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

SqlMapConfig.xml中配置的内容和顺序如下:

properties(属性)settings(全局配置参数)typeAliases(类型别名typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)

environments(环境集合属性对象)environment(环境子属性对象)transactionManager(事务管理)dataSource(数据源)mappers(映射器)

  •  mappers(映射器)Mapper配置的几种方法:
  • <mapper resource=" " />  使用相对于类路径的资源(现在的使用方式)  如:<mapper resource="sqlmap/User.xml" />
  • <mapper class=" " />  使用mapper接口类路径  如:<mapper class="cn.tzy.mybatis.mapper.UserMapper"/>

   注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

  • <package name=""/>  注册指定包下的所有mapper接口  如:<package name="cn.tzy.mybatis.mapper"/>

   注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。 

 

 

 ? mysql自增主键返回

 1 <!-- 保存用户 -->
 2 <insert id="saveUser" parameterType="com.tzy.mybatis.pojo.User">
 3     <!-- selectKey 标签实现主键返回 -->
 4     <!-- keyColumn:主键对应的表中的哪一列 -->
 5     <!-- keyProperty:主键对应的pojo中的哪一个属性 -->
 6     <!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
 7     <!-- resultType:设置返回的id的类型 -->
 8     <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int">
10         SELECT LAST_INSERT_ID()
11     </selectKey>
12     INSERT INTO user
13     (username,birthday,sex,address) VALUES
14     (#{username},#{birthday},#{sex},#{address})
15 </insert>
16 
17 //LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。

 

? Mysql使用 uuid实现主键

 1 <!-- 保存用户 -->
 2 <insert id="saveUser" parameterType="com.tzy.mybatis.pojo.User">
 3     <!-- selectKey 标签实现主键返回 -->
 4     <!-- keyColumn:主键对应的表中的哪一列 -->
 5     <!-- keyProperty:主键对应的pojo中的哪一个属性 -->
 6     <!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
 7     <!-- resultType:设置返回的id的类型 -->
 8     <selectKey keyColumn="id" keyProperty="id" order="BEFORE" resultType="string">
10         SELECT LAST_INSERT_ID()
11     </selectKey>
12     INSERT INTO `user`
13     (username,birthday,sex,address) VALUES
14     (#{username},#{birthday},#{sex},#{address})
15 </insert>
16 
17 //注意这里使用的order是“BEFORE”

 

? mybatis与hibernate不同
Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。 

 

标签使用:

if标签

 1 <!-- 根据条件查询用户 -->
 2 <select id="queryUserByWhere" parameterType="user" resultType="user">
 3 SELECT id, username, birthday, sex, address FROM `user`
 4 WHERE 1=1
 5 <if test="sex != null and sex != ‘‘">
 6 AND sex = #{sex}
 7 </if>
 8 <if test="username != null and username != ‘‘">
 9 AND username LIKE
10 "%"#{username}"%"
11 </if>
12 </select>
13 
14 //注意字符串类型的数据需要要做不等于空字符串校验。

 

 

where标签

 

上面的sql还有where 1=1 这样的语句,很麻烦
可以使用where标签进行改造

 1 <!-- 根据条件查询用户 -->
 2 <select id="queryUserByWhere" parameterType="user" resultType="user">
 3 SELECT id, username, birthday, sex, address FROM `user`
 4 <!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 -->
 5 <where>
 6 <if test="sex != null">
 7 AND sex = #{sex}
 8 </if>
 9 <if test="username != null and username != ‘‘">
10 AND username LIKE
11 ‘%${username}%‘
12 </if>
13 </where>
14 </select>

? Sql片段

 

Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。

 

把上面例子中的id, username, birthday, sex, address提取出来,作为sql片段,如下:

<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
<!-- SELECT id, username, birthday, sex, address FROM `user` -->
<!-- 使用include标签加载sql片段;refid是sql片段id -->
SELECT <include refid="userFields" /> FROM `user`
<!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 -->
<where>
<if test="sex != null">
AND sex = #{sex}
</if>
<if test="username != null and username != ‘‘">
AND username LIKE
‘%${username}%‘
</if>
</where>
</select>


<!-- 声明sql片段 -->
<sql id="userFields">
id, username, birthday, sex, address
</sql>

如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace

 

? foreach标签

 

向sql传递数组或List,mybatis使用foreach解析,如下:

 

根据多个id查询用户信息
查询sql:
SELECT * FROM user WHERE id IN (1,10,24)

 

如下图在pojo中定义list属性ids存储多个用户id,并添加getter/setter方法

技术分享图片

 1 UserMapper.xml添加sql,如下:
 2 <!-- 根据ids查询用户 -->
 3 <select id="queryUserByIds" parameterType="queryVo" resultType="user">
 4     SELECT * FROM `user`
 5     <where>
 6         <!-- foreach标签,进行遍历 -->
 7         <!-- collection:遍历的集合,这里是QueryVo的ids属性 -->
 8         <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 -->
 9         <!-- open:在前面添加的sql片段 -->
10         <!-- close:在结尾处添加的sql片段 -->
11         <!-- separator:指定遍历的元素之间使用的分隔符 -->
12         <foreach collection="ids" item="item" open="id IN (" close=")" separator=",">
14             #{item}
15         </foreach>
16     </where>
17 </select>

测试方法如下:

@Test
public void testQueryUserByIds() {
    // mybatis和spring整合,整合之后,交给spring管理
    SqlSession sqlSession = this.sqlSessionFactory.openSession();
    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    // 使用userMapper执行根据条件查询用户
    QueryVo queryVo = new QueryVo();
    List<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(10);
    ids.add(24);
    queryVo.setIds(ids);

    List<User> list = userMapper.queryUserByIds(queryVo);

    for (User u : list) {
        System.out.println(u);
    }

    // mybatis和spring整合,整合之后,交给spring管理
    sqlSession.close();
}

 

? 关联查询

   商品订单数据模型

? 一对一查询
需求:查询所有订单信息,关联查询下单用户信息。

注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询,因为一个用户可以下多个订单

? 方法一:使用resultType
使用resultType,改造订单pojo类,此pojo类中包括了订单信息和用户信息
这样返回对象的时候,mybatis自动把用户信息也注入进来了
? 改造pojo类
OrderUser类继承Order类后OrderUser类包括了Order类的所有字段,只需要定义用户的信息字段即可,如下图:

技术分享图片

? Mapper.xml
在UserMapper.xml添加sql,如下

<!-- 查询订单,同时包含用户数据 -->
<select id="queryOrderUser" resultType="orderUser">
SELECT
o.id,
o.user_id
userId,
o.number,
o.createtime,
o.note,
u.username,
u.address
FROM
`order` o
LEFT JOIN `user` u ON o.user_id = u.id
</select>

 

? Mapper接口
在UserMapper接口添加方法,如下图:

技术分享图片

? 测试方法:
在UserMapperTest添加测试方法,如下:

 1 @Test
 2 public void testQueryOrderUser() {
 3 // mybatis和spring整合,整合之后,交给spring管理
 4 SqlSession sqlSession = this.sqlSessionFactory.openSession();
 5 // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
 6 UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 7 
 8 // 使用userMapper执行根据条件查询用户
 9 List<OrderUser> list = userMapper.queryOrderUser();
10 
11 for (OrderUser ou : list) {
12 System.out.println(ou);
13 }
14 
15 // mybatis和spring整合,整合之后,交给spring管理
16 sqlSession.close();
17 }

测试结果如下图:

技术分享图片

定义专门的pojo类作为输出类型,其中定义了sql查询结果集所有的字段。此方法较为简单,企业中使用普遍。

 

 

? 方法二:使用resultMap
使用resultMap,定义专门的resultMap用于映射一对一查询结果。

? 改造pojo类
在Order类中加入User属性,user属性中用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个User对象存储关联查询的用户信息。
改造Order如下图:

技术分享图片

? Mapper.xml
这里resultMap指定orderUserResultMap,如下:

 1 <resultMap type="order" id="orderUserResultMap">
 2 <id property="id" column="id" />
 3 <result property="userId" column="user_id" />
 4 <result property="number" column="number" />
 5 <result property="createtime" column="createtime" />
 6 <result property="note" column="note" />
 7 
 8 <!-- association :配置一对一属性 -->
 9 <!-- property:order里面的User属性名 -->
10 <!-- javaType:属性类型 -->
11 <association property="user" javaType="user">
12 <!-- id:声明主键,表示user_id是关联查询对象的唯一标识-->
13 <id property="id" column="user_id" />
14 <result property="username" column="username" />
15 <result property="address" column="address" />
16 </association>
17 
18 </resultMap>
19 
20 <!-- 一对一关联,查询订单,订单内部包含用户属性 -->
21 <select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
22 SELECT
23 o.id,
24 o.user_id,
25 o.number,
26 o.createtime,
27 o.note,
28 u.username,
29 u.address
30 FROM
31 `order` o
32 LEFT JOIN `user` u ON o.user_id = u.id
33 </select>

 

 

? Mapper接口
编写UserMapper如下图:

技术分享图片

? 测试方法

 1 @Test
 2 public void testQueryOrderUserResultMap() {
 3     // mybatis和spring整合,整合之后,交给spring管理
 4     SqlSession sqlSession = this.sqlSessionFactory.openSession();
 5     // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
 6     UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 7 
 8     // 使用userMapper执行根据条件查询用户
 9     List<Order> list = userMapper.queryOrderUserResultMap();
10 
11     for (Order o : list) {
12         System.out.println(o);
13     }
14 
15     // mybatis和spring整合,整合之后,交给spring管理
16     sqlSession.close();
17 }

测试效果如下图:

技术分享图片

 

 

? 一对多查询
案例:查询所有用户信息及用户关联的订单信息。
用户信息和订单信息为一对多关系。

? 修改pojo类
在User类中加入List<Order> orders属性,如下图

技术分享图片

? Mapper.xml
在UserMapper.xml添加sql,如下:

 1 <resultMap type="user" id="userOrderResultMap">
 2     <id property="id" column="id" />
 3     <result property="username" column="username" />
 4     <result property="birthday" column="birthday" />
 5     <result property="sex" column="sex" />
 6     <result property="address" column="address" />
 7 
 8     <!-- 配置一对多的关系 -->
 9     <collection property="orders" javaType="list" ofType="order">
10         <!-- 配置主键,是关联Order的唯一标识 -->
11         <id property="id" column="oid" />
12         <result property="number" column="number" />
13         <result property="createtime" column="createtime" />
14         <result property="note" column="note" />
15     </collection>
16 </resultMap>
17 
18 <!-- 一对多关联,查询订单同时查询该用户下的订单 -->
19 <select id="queryUserOrder" resultMap="userOrderResultMap">
20     SELECT
21     u.id,
22     u.username,
23     u.birthday,
24     u.sex,
25     u.address,
26     o.id oid,
27     o.number,
28     o.createtime,
29     o.note
30     FROM
31     `user` u
32     LEFT JOIN `order` o ON u.id = o.user_id
33 </select>

? Mapper接口

技术分享图片

? 测试方法

 1 @Test
 2 public void testQueryUserOrder() {
 3     // mybatis和spring整合,整合之后,交给spring管理
 4     SqlSession sqlSession = this.sqlSessionFactory.openSession();
 5     // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
 6     UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 7 
 8     // 使用userMapper执行根据条件查询用户
 9     List<User> list = userMapper.queryUserOrder();
10 
11     for (User u : list) {
12         System.out.println(u);
13     }
14 
15     // mybatis和spring整合,整合之后,交给spring管理
16     sqlSession.close();
17 }

测试效果如下图:

 技术分享图片

 

以上是关于Mybatis内容记录的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis内容记录

markdown [mybatis参考]关于mybatis #mybatis的一些片段

MyBatis如何防止SQL注入

MyBatis怎么防止SQL注入

CSP核心代码片段记录

mybatis学习(39):动态sql片段