mybatis----基础

基础知识

  • 安装
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

对原生态jdbc程序中问题总结

  • 环境

java环境:jdk

  • jdbc程序

使用jdbc查询mysql数据库中用户表的记录

  • 问题总结
    • 数据库连接、使用时创建、不使用时就立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能(使用连接池管理数据库来连接进行优化)
    • 将sql语句硬编码到Java代码中,如果sql语句修改,需要重新编译代码,不利于系统维护(将sql语句配置在xml配置文件中,即使sql变化,也不需要对java代码进行重新编译)
    • 向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在Java代码中,不利于系统维护(将sql语句及占位符号和参数全部配置在xml中)
    • 从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护(将查询的结果集,自动映射成java对象。)

mybatis是什么

mybatis是一个持久层框架,是apache下的顶级项目。
mybatis是让程序员将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活的生成(半自动化,大部分需要程序员编写sql)满足需要的sql语句
mybatis可以将向preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象(输出映射)

mybatis框架

SqlMapConfig.xml     是mybatis的全局配置文件,配置了数据源、事务等mybatis运行环境(第三方软件进行配置)

mybatis自己还需要配置映射文件(mapper.xml、mapper.xml、mapper.xml……【映射文件】)也就是配置sql语句

SqlSessionFactory(会话工厂),根据配置文件创建工厂
作用:创建SqlSession
SqlSession(会话),是一个接口,面向用户(程序员)的接口
作用:操作数据库(发出增、删、改、查)
Executor(执行器),也是一个接口(基本执行器、缓存执行器)
作用:操作数据库(发出增、删、改、查)
mapped statement(底层封装对象)
作用:对操作数据库存储封装,包括sql语句,输入参数、输出结果类型

入门程序

  • 编写log4j.properties进行日志输出
# Global logging configuration
#在开发环境下日志级别要设置成DEBUG,生成环境设置成info或ERROR
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
  • 编写全局配置SqlMapConfig.xml
  • 映射文件
    • 映射文件命名
User.xml(原始mybatis命名),mapper代理开发映射文件叫xxxMapper.xml,比如:UserMapper.xml
在映射文件中配置sql语句
image.png

image.png

#{}与${}

  • #{} 表示一个占位符,#{}接受输入参数,类型可以是简单的类型,pojo、hashmap。
    如果接受简单类型,#{}中可以写成value或其他名称
    #{}接受pojo对象值,通过OGNL读取对象中的属性值,通过属性。属性。属性……的方式获取对象属性值
  • ${} 表示一个拼接符号,会引起sql注入,所以不建议使用
    ${}接受输入参数,类型可以是简单的类型,pojo、hashmap。
    如果接受简单类型,${}中只可以写成value

parameterType、resuletType

parameterType : 指定输入参数的类型
resuletType : 指定输出参数的类型

自增主键返回

mysql自增主键,执行insert提交之前自动生成一个自增主键。
通过mysql函数获取到刚插入记录的自增主键:
LAST_INSERT_ID()
是在insert之后调用此函数,需要修改UserInsert的定义

<insert id=“insertUser” parameter="cn.persist.entily.User">
    <!-- 
      将插入数据的主键返回,返回到user对象中
      SELECT LAST_INSERT_ID():得到刚insert进去的记录的主键的值,只适用于自增主键
      KeyProperty:将查询到的主键值parameterType指定的对象的哪个属性
      order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序
      resultType:指定SELECT LAST_INSERT_ID()的结果类型
     -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Inteager">
          SELECT LAST_INSERT_ID()
    </selectKey>
    <!--
          username,password,address是数据表中的对应的字段名称
          #{username},#{password},#{address}是实体类中对应的属性名
    -->
    INSERT into user(username,password,address) value(#{username},#{password},#{address})
</insert>

非自增主键返回(使用uuid)

使用mysql的uuid()函数生成主键,需要修改表中id字段类型为string,长度设置成35位
执行思路:
先通过uuid()查询到主键,将主键输入到sql语句中
执行uuid()语句顺序相对于insert语句之前执行

<insert id=“insertUser” parameter="cn.persist.entily.User">
    <!-- 
      使用mysql的uuid()生成主键
      执行过程:
      首先通过uuid()得到主键,将主键设置到user对象的id属性中
      其次在insert执行时,从user对象中取出id属性值
     -->
    <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
          SELECT uuid()
    </selectKey>
    <!--
          id,username,password,address是数据表中的对应的字段名称
          #{id},#{username},#{password},#{address}是实体类中对应的属性名
    -->
    INSERT into user(id,username,password,address) value(#{id},#{username},#{password},#{address})
</insert>

mybatis开发dao的方法

  • sqlSession使用范围
    • sqlSessionFactoryBuilder
      通过sqlSessionFactoryBuilder创建会话工厂sqlSessionFactory
    • sqlSessionFactory
      通过sqlSessionFactory创建sqlSession,通过单例模式管理sqlSessionFactory(工厂一旦创建,一直使用一个实例)
    • sqlSession
      是一个面向用户的接口(程序员)的接口
      sqlSession中提供了很多操作数据库的方法:例如:selectOne(返回单个对象)selectList(返回单个或多个对象)
      sqlSession是线程不安全的,在sqlSession实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性
      sqlSession最佳应用场合在方法体内,定义为局部变量使用

原始dao开发方法(程序员需要写dao接口和dao实现类)

  • 思路:

程序员需要写dao接口和dao实现类。
需要向dao实现类中注入sqlSessionFactory(会话工厂),在方法体内通过工厂(sqlSessionFactory)创建sqlSession

  • 总结原始开发dao的问题

1.dao的接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来
2.调用sqlSession方法时将statement的id硬编码了
3.调用sqlSession方法时传入的变量,由于sqlSession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,只有在运行时报错,不利于程序开发

mapper代理方法(程序员只需要mapper接口(相当于dao接口))

  • 思路

1.程序员只需要mapper接口(相当于dao接口),需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类的代理对象
2.程序员还需要编写mapper.xml映射文件

  • 开发规范:
    1.在mapper.xml中namespace等于mapper接口地址


    image.png

    2.mapper.java接口中的方法名和mapper.xml中statement的id一致
    3.mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致
    4.mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致


    image.png

    image.png

总结

以上开发规范主要是对下边的代码进行统一的生成:


image.png

SqlMapConfig.xml

  • properties(属性)

需求:
将数据库连接的参数单独配置在db.properties中,只需要在sqlMapConfig.xml中加载db.properties的属性值
SqlMapConfig.xml中就不需要对数据库连接参数硬编码
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一的管理,其他xml可以引用该db.properties

db.properties的文件

image.png

sqlMapConfig.xml加载属性名称

image.png

image.png

建议:
不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中

  • setting(全局配置参数)需要时设置,不需要就不要设置(会影响mybatis的运行)

mybatis框架在运行时可以调整一些运行参数
比如:开启二级缓存、开启延时加载……
全局参数将会影响mybatis的运行行为

  • typeAliases(类型别名)
    • 单个定义别名


      image.png
    • 批量定义别名


      image.png

在dao.xml中的返回值类型填实体类的名称,首字母大写小写都可以

  • typeHandles(类型处理器)

在mybatis中通过typeHandles完成jdbc类型和java类型的转换

  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境集合属性对象)
    • environment(环境子属性对象)
      • transactionManager(事务管理)
      • dataSource(数据源)
  • mappers(映射器)
    • 通过resource加载单个映射文件


      image.png
    • 通过mapper接口加载
      • 加载单个映射文件


        image.png
      • 批量加载映射文件(建议使用)


        image.png

动态sql

  • 什么是动态sql

mybatis核心就是对sql语句进行灵活的操作,通过表达式进行判断,对sql进行灵活拼接、组装

  • 需求:

用户信息总和查询列表和用户信息查询列表总数这两个statement的定义使用动态sql
对查询条件进行判断,如果输入参数不为空才能进行查询条件拼接;例如:

   <select id="findUserById" parameterType="User" resultType="user">
        select * from user
        <!--where 可以自动去掉条件中的第一个and-->
        <where>
            <if test="userCustom!=null">
                <if test="userCustom.usermame!=null and userCustom!=''">
                    and user.username = #{userCustom.username}
                </if>
                <if test="userCustom.sex != null and userCustom.sex != ''">
                    and user.sex = #{userCustom.sex}
                </if>
            </if>
        </where>
    </select>

sql片段

  • 需求:

将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其他的statement中就可以引用sql片段

  • 定义sql片段
    <!--定义sql片段
    id:sql片段的唯一标识
    经验:是基于表单来定义sql片段可重用性高
    在sql片段中不要包括where
    -->
    <sql id="query_user_where">
        <if test="userCustom!=null">
            <if test="userCustom.usermame!=null and userCustom!=''">
                and user.username = #{userCustom.username}
            </if>
            <if test="userCustom.sex != null and userCustom.sex != ''">
                and user.sex = #{userCustom.sex}
            </if>
        </if>
    </sql>

应用sql片段

<select id="findUserById" parameterType="User" resultType="user">
        select * from user
        <!--where 可以自动去掉条件中的第一个and-->
        <where>
            /*应用sql片段*/
            <include refid="query_user_where" />
            /*在这里还会引用其他的sql片段*/
        </where>
    </select>

foreach

向sql传递数组或list,mybatis使用foreach解析

  • 需求

在用户查询列表和查询总数的statement中增加多个id输入查询
sql语句如下:
select * from user where id=1 or id=10 or id=16select * from user where id in(1,10,16)

  • 在输入参数类型中添加List<Integer>传入多个id
    private List<Integer> ids传入多个id
  • mapper.xml的配置

在查询条件中,查询条件定义成一个sql片段,需要修改sql片段

<!--定义sql片段
   id:sql片段的唯一标识
   经验:是基于表单来定义sql片段可重用性高
   在sql片段中不要包括where
   -->
    <sql id="query_user_where">
        <if test="ids!=null">
            <!--使用foreach遍历传入ids
            collection:指定输入对象中集合属性
            item:每次遍历生成的对象
            open:开始遍历时拼接的串
            close:结束遍历时拼接的串
            separator:遍历的两个对象中需要拼接的串
            -->
            <foreach collection="ids" item="user_id" open="and (" close=")" separator="or">
                /*每次遍历需要拼接的串*/
                id=#{user_id}
            </foreach>
        </if>
    </sql>

select * from user where id in(1,10,16)的foreach查询方法

image.png

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 使用原生jdbc的问题 数据库连接, 使用时就创建,不使用就立即释放,对数据库进行频繁地链接开启和关闭,造成数据库...
    wtmxx阅读 717评论 1 3
  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,422评论 0 4
  • 1.1mybatis下载 mybaits 的代码由github.com 管理,地址:https://github....
    暖熊熊阅读 852评论 0 5
  • 进入工作以来一直被认为是一个没有目标感的人,常常怀揣着感性的想法去看待人与人之间的关系,并不受到上司的喜欢...
    怀旧的小矫情阅读 233评论 0 0
  • 凉如水的双眼(原创) 清晨的时候有一股蓝烟腾起,是的,一股淡薄的烟雾袅袅散布于青林之上。苍天是...
    秋色文学烈火的轻云阅读 161评论 0 0