Mybatis笔记

来源:互联网 发布:大数据分析就业 编辑:程序博客网 时间:2024/06/06 03:40

Mybatis知识点

1.mybatis是什么?

mybatis是一个持久层的框架,是apache下的顶级项目。

mybatis提供映射方式,自由灵活生成满足需要的sql语句。

可以将向preparedstatement中的输入参数自动进行输出映射。将查询结果集自动映射成java对象。(输出映射)

2.mybatis框架


3.入门程序

需求:根据用户id查询数据

根据用户名称模糊查询数据

              删除、添加、更新用户。

要下载mybatis的jar包。https://github.com/mybatis/mybatis-3/releases

过程:

1.    创建一个po类

2.    创建映射文件,在映射文件中配置sql

<!-- namespace在这里是指数据库实例的名称 -->

<mappernamespace="orcl

">

<!-- 在这里配置sql语句 -->

<!-- 通过select完成查询 -->

            <!-- 通过id查询用户

             #{} 表示一个占位符

             parameterType 表示参数的类型

             #{id} 表示接入输入的参数是id,如果输入的是简单类型,则参数可以是任意,可以是value

             ResultType表示操作数据库结果所映射的Java对象类型

             select中的ResultType表示查询结果的一条记录转成一个对象,般为包名.类名

              -->

<selectid="finduserbyid"parameterType="java.lang.Integer"resultType="com.ly.domain.User">

    select* from user where id=#{id}

</select>

</mapper>

3.    在SqlMapConfig文件中配置映射文件的加载。

 <mappers>

    <mapperresource="sqlmap.User.xml"/>

   </mappers>

4.    编写测试第一条(按id查询)

1)在xml中配置sql:

<!--通过select完成查询 -->

               <!-- 通过id查询用户

                #{} 表示一个占位符

                parameterType 表示参数的类型

                #{id} 表示接入输入的参数是id,如果输入的是简单类型,则参数可以是任意,可以是value

                ResultType表示操作数据库结果所映射的Java对象类型

                select中的ResultType表示查询结果的一条记录转成一个对象

                -->

    <selectid="finduserbyid"parameterType="java.lang.Integer"resultType="com.ly.domain.User">

        select * from users where id=#{id}

</select>

2)编写测试代码:

public classMybatisFirst {

  //根据id查询用户信息

  @Test

  public static void finduserbyid() throwsException{

          //配置文件

          String str ="SqlMapConfig.xml";

          InputStream ips = null;

          SqlSessionFactory sessionfeactory =null;

          SqlSession ss=null;

          try {

                  //得到配置文件输入流

                  ips =Resources.getResourceAsStream(str);

                  //创建会话工厂,传入mybatis文件的配置信息。

                   sessionfeactory= newSqlSessionFactoryBuilder().build(ips);

                  //通过工厂得到sqlsession

                  ss = sessionfeactory.openSession();

                  //通过sqlsession操作数据库

                           //第一个参数:statement中的id=namespace+.+statement的id

                           //第二个参数:指定和映射文件中所匹配的parameterType的类型参数,也就是表中某一记录的id

                  User user=ss.selectOne("orcl.finduserbyid",1);

                           System.out.println(user);

          } catch (IOException e) {

                  // TODO Auto-generated catchblock

                  e.printStackTrace();

          }finally{

                  //关闭资源

                  ss.close();

                  ips.close();

                  //((InputStream)sessionfeactory).close();

          }      

  }

}

5.  编写测试第二条(按名字模糊查询)

1)在User.xml中添加配置信息:

<!--${}表示拼接sql,即把传入的sql参数不加修饰拼接起来-->

<selectid="finduserbyname"parameterType="java.lang.String"resultType="com.ly.domain.User">

        select * from users where name like‘%${value}%’

 </select>

2)编写测试代码:

public voidfinduserbyname(){

             SqlSessions2 = null;

             try {

                  s2=common();

                 List<User>list = s2.selectList("orcl.finduserbyname","");

                 for(User i:list){

                     System.out.println(i.getId()+"——————"+i.getName());

                 }

             } catch (IOExceptione) {

                 // TODOAuto-generated catch block

                 e.printStackTrace();

             }finally{

                 s2.close();

             }

        }

6.  编写第三条(添加信息)

1)在xml文件中配置:

<!-- 添加用户

  此时的参数类型应该时domain类,

  #{}中写的是domain类中的属性,mybatis通过ognl获取对象的属性值-->

    <insertid="addUser"parameterType="com.ly.domain.User">insert intousers(id,name) values(#{id},#{name}) </insert>

2)编写测试代码

public void addUser(){

          SqlSession s3=null;

          try {

              s3 = common();

              User user = new User();

              user.setId(5);

              user.setName("倩倩");

              s3.insert("orcl.addUser",user);

              s3.commit();

          } catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          }

}

7.  删除用户

a)   Xml配置:

<!-- 删除用户-->

    <deleteid="deleteUser"parameterType="java.lang.Integer">DELETE FROM USERS WHEREID=#{ID}</delete>

b) 编写测试代码:

public void deleteUser(){

       SqlSession s4=null;

       try {

          s4 = common();

          s4.delete("orcl.deleteUser", 6);

          s4.commit();

       } catch (IOException e) {

          // TODO Auto-generated catch block

          e.printStackTrace();

       }finally{

          s4.close();

    }

8.  修改用户

a)  xml配置

<!-- 根据id修改用户 -->

  <updateid="updateUserById"parameterType="com.ly.domain.User">

    updateusers set name=#{name} where id=#{id}

 </update>

b) 编写测试文件

publicvoid updateUserById(){

    SqlSessions5=null;

    try{

        s5= common();

        Useruser = new User();

        user.setName("李燕燕");

        user.setId(4);

        s5.update("orcl.updateUserById",user);

        s5.commit();

    }catch (IOException e) {

        //TODO Auto-generated catch block

        e.printStackTrace();

    }finally{

        s5.close();

    }

}

总结:

1、参数如果只有一个,parameterType为属性类型。超过一个,参数为对象(包名.类名)。

2、单元测试文件(Junit)应该导入三个包。

3、如果没有涉及到Dao层,则命名空间为数据库实例名,如果用到则为:dao接口的包名.类名。

4、#{}和${}的区别?

#{}表示一个占位符,接受传入的参数。传入的参数类型可为:简单类型,value,pojo对象,HashMap。当传入的是简单数据类型时,可写成value或其他名称。${}表示sql拼接,会引起sql注入,不建议使用,接受传入的参数,类型可为:简单类型,value,pojo对象,当传入的是简单类型,则只能为value。

9.  自增主键返回

1)    Mysql自增:执行insert提交之前,自动生成自增主键。通过mysql的函数获取最新增加的主键。LAST_INSERT_ID(unsert之后调用)

      Xml配置:

<!--只适用于mysql中的自增长主键

    keyProperity:将获取到的主键值设置到parameterType中的那个属性中

    order:sql语句的执行顺序,相对于insert语句的查询顺序

     -->

    <selectKeykeyProperty="id"order="AFTER" ResultType="java.lang.String">SELECT LAST_INSERT_ID</selectKey>

2)    Oracle自增:通过序列

<selectKey keyProperty="id"order="AFTER" resultType="java.lang.Integer">SELECT序列名.nextval</selectKey>

3)    Sql server自增:

10.     非自增主键

a)  Mysql:使用uuid函数实现主键的非自增。需修改主键的类型为String,长度为35.即先用uuid随机生成一个id号,然后将主键放入sql中。

<selectKeykeyProperty="id" order="AFTER" resultType="java.lang.Integer">SELECTUIDD</selectKey>

b) Oracle:

11.     Mybatis常用的接口和类:

1)    SqlSession使用范围:是一个面向用户的接口。SqlSession提供很多操作数库的方法。(SelectOne,SelectList)线程不安全,在实现类中除了有操作数据库的方法,还有数据域的属性。最佳应用场合在方法体中,定义成局部变量。

2)    SqlsessionFeactory:通过SqlsessionFeactory来创建SqlSession。使用单例模式创建SqlSessionFeactory。

3)    SqlsessionFeactoryBuilder:通过SqlSessionFeactoryBuilder来创建SqlSessionFeactory。

12.     开发dao层:

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

需要向dao实现类中注入SqlSessionFeactory,然后再创建SqlSession。

a)  dao接口:

publicinterface UserDao {

    //根据id查询用户信息(由xml实现)

    public User finduserbyid(int id) throwsException;

    //添加用户信息

    public void addUser(User user) throwsIOException;

    //删除用户

    public void deleteUser(int id);

}

b)  dao接口实现类:

publicUser finduserbyid(int id) throws Exception {

        // TODO Auto-generated method stub

        SqlSession sqlsession = MybatisFirst.common();

        User user =sqlsession.selectOne("orcl.finduserbyid",id);

        sqlsession.close();

        return user;

    }

2)    Mapper代理方法(只需要写mapper接口)

写个mapper接口(dao接口)

   public interface UserDaoMapper {

   //根据id查询用户信息(由xml实现)

   public User finduserbyid(int id) throws Exception;

   //添加用户信息

   public void addUser(User user) throws IOException;

   //删除用户

   public void deleteUser(int id);

}

编写mapper.Xml映射文件

   开发规范:“

a)  Namespace是包名.类名。

b)  Mapper.java中的方法名是mapper.Xml中的id

c)  Mapper.java中方法的返回值是mapper.xml中的resultType。

d)  Mapper.java中方法的参数是mapper.xml中的parameterType。

13.     SqlMapConfig.xml

Mybatis的全局配置文件:

   <configuration> 

    <environmentsdefault="development"> 

        <environmentid="development"> 

            <transactionManagertype="JDBC"/> 

            <dataSourcetype="POOLED"> 

                <propertyname="driver"value="oracle.jdbc.OracleDriver"/> 

                <propertyname="url"value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> 

                <propertyname="username"value="Test"/> 

                <propertyname="password"value="test"/> 

            </dataSource> 

        </environment> 

    </environments> 

    <!-- 加载映射文件 -->

    <mappers>

    <mapperresource="com/ly/mapper/UserMapper.xml"/>

    </mappers>

</configuration> 

1>  Properties属性

将url和driver,password,username配置在db.properties文件中,在需要的xml文件中用${username}…拼接。

<propertiesresource=”db.properties”></properties>

 

Mybatis加载属性的顺序:

    在properties元素体内定义的属性首先被读取

    然后会读取properties中的resource或者是url加载的属性,会覆盖已读取的同名属性。

    最后读取parametertype传递的属性。会覆盖已读取的同名属性。

优先级:parametertype——resource——properties

2>  Setting属性

调整运行参数(开启二级缓存等)

3>  typeAlias(别名)

针对单个的别名定义:

<typeAliases>

<typeAlias type=”全路径” alias=”别名”>

</typeAliases>

    批量定义别名:输入一个包名,会自动给所有po类定义别名。别名是类名,首字母大小写都可以。

<typeAliases>

<typeAlias type=”包名” >

</typeAliases>

4>  映射配置

<mappers>

单个映射文件的加载:

<mapper resource=”相对路径”>

通过mapper接口加载映射文件,规范,需将mapper接口类和mapperxml文件同名且放在一个目录下。这种方法的前提是使用了mapper代理的方法。

<mapper class=”接口的路径”/>

批量加载映射文件。规范,需将mapper接口类和mapperxml文件同名且放在一个目录下。这种方法的前提是使用了mapper代理的方法。

<package name=mapper接口的包名”>

</mappers>

14.     输入参数映射

通过parametertype可指定输入类型。可以是:pojo包装类型,简单类型,hashmap类型。

Pojo包装对象做参数:

   写一个查询条件包装类(假设为ComUser),再写一个扩展类。把需要的查询条件加入进去。

Xml配置:

   ParameterType=”查询条件包装类的路径” 用${原pojo包装类名.属性名}获取传入的参数。

<select id=”comquery”parameterType=”查询条件包装类路径”>

SELECT SNO FROM USERSWHERE ID=${扩展类.id} AND SEX=${扩展类.sex}

15.     输出参数映射

1>  Resulttype

使用resultType进行映射输出时,只有查询的字段和pojo类中属性名一致时才可以映射成功。

如果查询的字段名和pojo类中的字段都不一致,那么不会创建pojo对象。

如果查询的字段明和pojo类中有至少一个字段一致,那么会创建pojo对象。

输出简单类型:

ResultType=“int/String/Date…“

2>  resultMap

如果查询的字段和pojo的属性不一致,定义一个resultMap对列明和pojo属性名之间做一个映射关系。

a)  定义resultMap

<!-- 定义resultMap

Type:resultmap最终所映射的Java对象类型,可以使用别名

id:对resultmap的唯一标识 -->

        <resultMaptype="User"id="UserresultMap">

    <!-- column:查询出的列名

propertyresultmappojo类型中的属性名 -->

<idcolumn=""property=""/>

    <!-- 对普通列的映射定义 -->

<resultcolumn=""property=""/>

    </resultMap>

b)  使用resultMap作为statement输出映射类型

   <selectid="finduserbyid"parameterType="java.lang.Integer"resultMap="刚才定义的resultmap">

        select * from users where id=#{id}

    </select>

如果此时用的resultmap是其他xml文件中的,则需要再调用时加上命名空间。

16.     动态sql

Mybatis的核心是,对sql语句进行灵活操作,通过表达式进行判断,对sql语句进行灵活拼接。

对传入的参数进行判断:如果不为空,则传入

用if进行判断。

        <selectid="finduserbyid"parameterType="java.lang.Integer"resultType="com.ly.domain.User"> 

        select * from users

    <where>

               <iftest="id!=null and id!=''">and id=#{id}</if>

               <iftest="name!=null and name!=''">and name like'%${name}%'</if>

    </where>

    </select>

17.     Sql片段

A)     定义:

<!-- 定义sql片段 ,基于单表定义sql片段,可重用高,sql片段中不要包含where-->

<sqlid="query_User_where">

     <iftest="id!=null and id!=''">and id=#{id}</if>

     <iftest="name!=null and name!=''">and name like'%${name}%'</if>

    </sql>

B)    使用:

<where>

    <!-- refid:指定sql片段的id,如果引用的sql片段不在当前xml中,需要加namespace -->

    <includerefid="query_User_where"></include>

 </where> 

18.     Foreach标签

19.     一对一查询

mapper.Xml中定义resultmap:

<resultMaptype="返回类型"id="用于表示这个resultmap">

    column:查询出的列名

    propertyresultmappojo类型中的属性名

    <id column=""property=""/>

    对普通列的映射定义

    <result column=""property=""/>

<!--association:用于映射关联查询单个用户的信息

    property:要将关联查出来的信息映射到主信息pojo类的那个属性中 -->

    <associationproperty="" javatype=“映射的java类型“></association>

    <id cloumn=” ” property=” ”/>

    <result cloumn=” ” property=” ” />

    </resultMap>

配置映射关联的用户查询信息:

总结:

   如过没有特殊要求,比如把查到信息的用户相关信息返回到一个user对象中,则使用resulttype。只需要把没有的字段对应的属性加入到pojo类中即可。

   若是有特殊要求,则使用resultmap。进行resultmap定义时,关联的信息用标签association。进行配置。

   Resultmap可以实现延迟加载,resulttype不可以。

20.    一对多查询

(比如:查询订单和订单明细)

定义resultmap:

   <resultMaptype="返回类型"id="用于表示这个resultmap">

    column:查询出的列名

    propertyresultmappojo类型中的属性名

    <id column=""property=""/>

    <!--对普通列的映射定义-->

    <result column=""property=""/>

<!--association:用于映射关联查询单个用户的信息

    property:要将关联查出来的信息映射到主信息pojo类的那个属性中 -->

    <associationproperty="" javatype=“映射的java类型“></association>

    <id cloumn=” ” property=” ”/>

    <result cloumn=” ” property=” ” />

<!--订单明细信息 一个订单明细查询多条明细,要使用collection进行映射。collection是把查询出的多条结果映射到一个集合中-->

        <collectionproperty="映射的类的那个属性"ofType="要映射到集合属性中pojo的类型">

        <id column=”订单明细的主键(注意取别名)” porperity=”属性名/>

        <result/>

        </collection>

    </resultMap>

由于上边很多配置信息重复,所以可使用继承属性,提高代码的复用率。

    <!-- 一对多查询的resultmap,和一对一查询映射重复的可以不用重新配置,直接用继承。 -->

    <resultMaptype=""id=""extends=" 一对一查询的resulttypeid">

    <!-- 订单信息 -->

    <!-- 用户信息 -->  

    <!-- 订单明细信息 一个订单明细查询多条明细,要使用collection进行映射。collection是把查询出的多条结果映射到一个集合中-->

        <collectionproperty="映射的类的那个属性"ofType="要映射到集合属性中pojo的类型">

        <id/>

        <result/>

        </collection>

    </resultMap>

总结:

Mybatis使用collection对多条关联信息映射到一个list集合属性中。如果使用resultype将订单明细信息映射到pojo类的定义的类对象属性中。需要自己处理:双重循环遍历,去重,加入list集合中。

21.     多对多查询

定义resultmap:

<resultMaptype="user"id="id">

    <idcolumn=""property=""/>

    <resultcolumn=""property=""/>

    <!-- 订单信息 ,一个用户对u应多个订单信息,所以用collection-->

    <collectionproperty="映射类的属性"ofType="要映射到集合中的pojo类型,即是list集合里放置的东西">

    <id/>

    <result/>

    <!-- 订单明细信息 一个订单明细查询多条明细,要使用collection进行映射。collection是把查询出的多条结果映射到一个集合中-->

        <collectionproperty="映射的类的那个属性"ofType="要映射到集合属性中pojo的类型">

        <id/>

        <result/>

        </collection>

        <!-- 商品信息,一个商品信息对应一个商品-->

        <associationproperty="商品明细表对应的对象"javaType="商品信息表对应的pojo">

        <idcolumn=""property=""/>

        <resultcolumn=""property=""/>

        </association>

    </collection>

    </resultMap>

总结:

   对查询结果有特殊要求的功能,使用resultmap。若没有,仅仅是把结果映射到一个list集合中时,仅仅需要用resulttype。

22.     resultType和resultMap的总结:

resulttype:

作用:将查询结果按照sal列名,pojo属性名映射到一个pojo对象中

场合:常见一些记录的明细。比如商品明细,将关联信息全部显示在页面时,可直接适应resulttype将每一条记录映射到一个rojo对象中,在前端页面遍历list集合即可。

      resultMap

作用:使用association和collection完成一对一和一对多高级映射。

      Association

作用:将关联查询信息映射到一个pojo对象中

场合:比如查询订单和用户关联信息。为查询方便可以把订单信息映射到用户对象的pojo属性中。

   Collection

作用:将关联信息映射到一个list中。

场合:比如查询模块权限范围下的信息。可将模块名称映射到list中。再将权限下的信息映射到对象模块中的list下。

23.     延迟加载

Association和collection有延迟加载的功能。

假如说你需要查询订单并且关联查询用户信息。则可以先查询商品订单,在需要时再去查询用户信息。把对用户信息的按需求去查询,就是延迟加载。

延迟加载:先查询简单的,即先从单表查询,再去从单表中关联查询。大大提高数据库性能。

1)     Mapper.Xml

思路:定义连个statement语句。第一个:查询订单。第二个:查询用户信息。在查询订单的statement中使用association实现对第二个(用户信息)查询的延迟加载。

延迟加载的resultmap(使用association):

<resultMaptype="orders"id="lazy">

        <!-- 对订单信息的配置 -->

            <id/>

            <result/>

        <!-- 对用户信息实现延迟加载 -->

            <associationproperty="user"javaType="User"select="指定延迟加载所需要执行的sql语句(statementid"column="两次查询关联查询的列">

            </association>

    </resultMap>

2)     延迟加载配置

Mybatis默认不开启延迟加载。需要在sqlmapconfig.xml用setting进行配置。

LazyLoadingEnabled: 全局性设置懒加载。如过为false。则全部相关信息都被初始化。默认false。

AggressiveLazyloading:当设置为true时,所有的懒加载对象可能被任何属性全部加载。否则每个属性按需加载。默认true。

<setting>

        <settingname="LazyLoadingEnabled"value="true"/>

        <Settingname="AggressiveLazyLoading"value="false"/>

</setting>

总之,使用延迟加载就是先去查询简单信息,再去查询关联信息。

24.     缓存

 

 

 

 

 

 

 

 

 

 

 

 

一级缓存是sqlsession缓存:操作数据库时,需要先创建一个sqlsession会话,sqlsession中有一个数据结构(hashmap)用于缓存数据,不同的sqlsession之间不影响。

二级缓存是mapper缓存:多个sqlsession去操作同一个mapper的sql语句。多个sqlsession去操作数据库得到的数据会存在二级缓存区域。即二级缓存是跨sqlsession的。

       缓存中如果有,则不需要去数据库查找,提高系统性能。

25.一级缓存

工作原理(以按id查询为例):

                                                Sqlsession写入

 

 

 

                                                                                     清空

 

 

 

读取

                                                                                                                                             

 

 

第一次发出查询请求,先去缓存区域看有没有,如果没有,则去数据库找,得到用户信息,存储在一级缓存中。第二次查询去缓存中直接存取。注意:如果两次之间有了commit,则会清空缓存中关于这个数条数据的信息。避免脏读。

 

26.二级缓存

工作原理:

 

 

 

 

 

 

 

 

 


                                                                                                                                             

                                  写入

                                                                                   读取                                         清空

 

 

 

 

 

 

 

同理,如果另一个sqlsession进行提交,也会清空该二级缓存下的缓存。

二级缓存比一级缓存区域大。二级缓存可以跨Sqlsession。每个mapper(按照namespace分)有一个缓存区域。

前提:开启二级缓存。

在sqlmapconfig文件中开启:

<setting name=”cacheEnabled”value=”true”/>

在usermapper中开启:

       <cache/>

应用场景:

适用于用户访问多,实时性不高的查询。或者耗时的sql语句时。设置刷新频率(flushInterval)为24h,30min等等。

       局限性:

比如京东的商品信息,一发生变化,则需要立即被用户知道。假设有一个商品有了commit请求,则需要全部清空缓存。即对细粒度缓存不好。

27.Mybatis整合encache

使用分布缓存对缓存数据进行整合管理。Mybatis无法实现整合缓存,所以需要和其他缓存框架进行整合。实现cache接口。

配置xml文件:

       <cache type=”使用的cache类型,默认使用perpetualCache”/>

要和encache整合,type配eneache的实现类。(先导包)

创建一个encache.Xml文件: