基础复习9-mybatis

配置:http://www.mybatis.org/mybatis-3/zh/configuration.html(上面写的很清楚)

Mybatis是一个轻量级ORM框架(持久层框架),前身为ibatis是apache软件基金会的一个开源项目,后来迁移到google code并更名为Mybatis。框架本身注重sql与pojo之间的映射关系

IDEA不会编译src下的java目录下的xml文件的,所以找不到xml文件,所以pom.xml里面需要配置

https://bglmmz.iteye.com/blog/2063856

http://www.cnblogs.com/tcming/p/7122124.html

<resources>

      <resource>

        <directory>src/main</directory>

        <includes>

          <include>**/*.xml</include>

          <include>**/*.properties</include>

        </includes>

      </resource>

    </resources>

一、Mybatis环境搭建

  1. 在项目中添加mybatis的支持库(mybatis-x.x.x.jar)
  2. 2.添加mybatis的核心配置文件(mybatis-config.xml)

层级结构:

A.属性配置

B.别名配置

C.环境配置

   C1事务配置

   C2.数据源配置

D.映射配置

3.(可选)添加jdbc.properties文件,提供数据库连接相关的字符串

4.添加实体类(DTO)、Mapper(DAO)接口以及Mapper接口的映射文件

 

二、Mybatis配置eclipse提示

  1. 解压mybatis.jar包
  2. 找到org/apache/ibatis/builder/mybatis-3-config.dtd

  org/apache/ibatis/builder/mybatis-3-mapper.dtd

     3.windows->preferences->xml->xml catalog->add->

基础复习9-mybatis

三、Mybatis-config核心配置类的一些配置

TypeAliases:别名,在mapper.xml中也生效(parameterType、resultType)

<package name=”com.wan.pojo”> 默认为类名小字母手写

<typeAlias type="com.wan.pojo.User" alias="user"></typeAlias>

 

注解@Alias(“myuser”):(放在POJO类上)

优先于别名

Properties:配置属性资源路径

Properties里面还可以自己加<property>属性,jdbc.properties实际上也是加载成了属性

基础复习9-mybatis

< Properties url=”file:/d:”/jdbc.properties”>存在于本地磁盘中(绝对路径)

< Properties url=”http://www.wan.com/jdbc.properties”>存在于本地磁盘中

< Properties resource=”jdbc.properties”>存在于项目中(相对路径)

Environment:环境配置,id是可以自己定义的,default指定一个id就可以了。

基础复习9-mybatis

transactionManager:事务管理器

JDBC:默认关闭事务的自动提交,再手动提交

MANAGER:放弃事务管理,由其他事务管理器管理(如SPRING的管理器会覆盖前面的配置-AOP)

dataSource:数据源  使用连接池机制,

       UNPOOLED:不使用连接池

       POOLED:使用mybatis提供的默认连接池

       JNDI:一般用于web项目中,主要通过在web容器(tomcart,jboos)中配置获取数据源

Mappers:映射配置

<mapper resource=”com/wan/mapper/UserMapper.xml”>:一次配置一个

<package name=”com.wan.mapper”>:一次配置多个

<mapper class=”com.wan.mapper.IUserMapper”>:直接配置在接口上,则没个方法上加注解写sql语句

基础复习9-mybatis

<mapper url=”file:----”>:配置本地文件

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--配置属性资源路径(JDBC连接信息)-->
   
<properties resource="jdbc.properties"></properties>
    <typeAliases>

    </typeAliases>
    <!--配置sqlSessionFactory的环境-->
   
<environments default="development">
        <environment id="development">
            <!--事务管理器-->
           
<transactionManager type="JDBC"/>
            <!--数据源  使用连接池-->
           
<dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--配置映射文件路径-->
       
<mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>

属性文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=

-----------------------------------------------------------------

映射文件:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.softeem.mapper.IUserMapper">

 <!--

    id保持与接口中方法名一致

  -->

  <!-- 查询操作 -->

  <select id="selectAll" resultType="User">

    select * from tbuser

  </select>

 

  <select id="findById" resultType="User">

    select * from tbuser where id=#{uid}

  </select>

 

  <!-- 插入语句 -->

  <insert id="insert" parameterType="User">

    insert into tbuser(username,password) values(#{username},#{password})

  </insert>

 

</mapper>

 

四、Mapper.xml映射文件配置

返回插入主键列为返回值(MySQL、SQLServer)(ORACLE自动递增不可以用这种方法)

基础复习9-mybatis

#{XX}  如果参数类型是基本类型,写什么都无所谓,如果是引用类型则必须与属性名相同

设置属性与列的映射关系

如果数据库列明与属性不同要配置,否则查找操作映射属性时相应属性取不到值,例如uid与表中id字段不一致,则uid取不到值。

基础复习9-mybatis

基础复习9-mybatis

用as设置列的别名也可以解决列明与属性名不一致的问题(从这里可以看出,是根据数据库列明进行反射得到属性的Getter方法进行属性赋值)

基础复习9-mybatis

基础复习9-mybatis

 

注:返回值int仍然是改变列的个数

user.getUid()才能得到主键列

 基础复习9-mybatis

基础复习9-mybatis

基础复习9-mybatis

 

五、多表关联查询

多对1或1对1:例如Users类里面Groups类属性

association:关联【column列一定要写,关联列】

基础复习9-mybatis

1对多:Groups类里面有users = List<Users>属性

javaType:java集合类型

ofType:List中属性的类型

collection:

实现方法1:

<resultMap type="groups" id="groupUserInfo" autoMapping="true">
    <id property="gid" column="gid"></id>
    <collection property="userList" fetchType="eager" autoMapping="true" javaType="java.util.ArrayList" ofType="com.wan.pojo.User"

select="com.wan.mapper.IUserMapper.selectByGid">
    </collection>
</resultMap>

 

实现方法2:

这种方法实际上是执行了两条sql语句

GroupMapper.xml

<resultMap type="group" id=" groupInfo" autoMapping="true" >

    <association property="userList" fetchType="eager" column="gid" javaType="List" ofType=”user” autoMapping="true" select="com.wan.mapper.IUserMapper.selectByGid"></association>
</resultMap>
<select id="selectByPrimaryKey"  resulMap="groupInfo ">

    select * from user where gid = #{gid}
</ select >
 
 
UserMapper.xml:
<select id="selectByGid"  resulType="users ">

    select * from user where gid = #{gid}
</ select >
 
IUserMapper

基础复习9-mybatis

IGroupMapper

Public Group selectByPrimaryKey(int gid);

 

六、动态sql

a、任意多个列组合模糊查询

  1. 可以用concat这些字段
  2. or语句(但如果列很多不适用)
  3. <if> <> <>语句

If中用and 和or连接条件

<bind>是声明变量的意思

Like用concat连接

<select id="selectByCondition" resultMap="userInfo">
   
    select * from tbuser
    where password = 123
    <
if test="username != '' and username != null">

        <bind name="name" value="'%'+username+'%'"></bind>

        /*or username like #{name}*/
        or username like CONCAT('%',#{username},'%')
    </
if>

<if test="uid != '' and uid != null">

        and id = #{uid}

</if>

</select>

基础复习9-mybatis

b、多个条件只选其一,switch

按照when的顺序来匹配

<choose>

       <when>

       <when>

<choose>

基础复习9-mybatis

c、多个set组合

基础复习9-mybatis

d、多个insert into值

insert into tbemp(xxx) values(xxx);

基础复习9-mybatis

基础复习9-mybatis

e、多个delete from xxx where id in(xxxxx)

基础复习9-mybatis

基础复习9-mybatis

 

七、基于注解的mapper配置,摆脱xml文件的配置

例:查某groups,属性userList

基础复习9-mybatis

基础复习9-mybatis

<resultMap type="groups" id="groupUserInfo" autoMapping="true">
    <id property="gid" column="gid"></id>
    <collection property="userList" fetchType="eager" autoMapping="true" javaType="java.util.ArrayList" ofType="com.wan.pojo.User"

select="com.wan.mapper.IUserMapper.selectByGid">
    </collection>
</resultMap>

 

八、延迟加载

如果是EAGER,那么表示取出这条数据时,它关联的数据也同时取出放入内存中

如果是LAZY,那么取出这条数据时,它关联的数据并不取出来,在同一个session中,什么时候要用,就什么时候取(再次访问数据库)。

但是,在session外,就不能再取了。用EAGER时,因为在内存里,所以在session外也可以取。

一般只在一边设Eager,JPA接口默认为一对多为Lazy,多对一为Eager,但是Hibernate反向工程生成Entity时,多对一为Lazy,需要手动改为Eager。

而两边都设Eager,那么代码中取一条记录时,会发2次SQL

在开发时,经常有这种需求,我拿到了一个order表单实体时,我需要知道该表单是属于哪个用户的。

这时访问 order.getUser() 获取用户信息,这时应该得到一个用户的信息实例。

解决这个问题的方法有三种:

1、通过1条SQL语句进行关联查询,同时读取表单和用户信息;

2、同时发送2条SQL,用于读取 order 与 user信息;

3、先用1条SQL读取order表单信息,访问getUser()时再用另1个SQL读取user信息;

第一种方法:使用关联查询的 mapper 的配置

1    <resultMap type="cn.xleos.mybatis.po.Order" id="orderUserMap">

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

 3     <result property="createtime" column="orders_createtime" />

 4     <result property="number" column="orders_number" />

 5     <result property="note" column="orders_note" />

 6     <association property="user" javaType="cn.xleos.mybatis.po.User">

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

 8         <result property="username" column="user_username" />

 9         <result property="birthday" column="user_birthday" />

10         <result property="sex" column="user_sex" />

11         <result property="address" column="user_address" />

12     </association>

13 </resultMap>

14 <select id="getOrdersAndUser">

15     SELECT

16     orders.id AS orders_id,

17     orders.number AS orders_number,

18     orders.createtime AS orders_createtime,

19     orders.note AS orders_note,

20     `user`.id AS user_id,

21     `user`.username AS user_username,

22     `user`.birthday AS user_birthday,

23     `user`.sex AS user_sex,

24     `user`.address AS user_address

25     FROM orders

26     INNER JOIN `user` ON `user`.id = orders.user_id

27     </select>

第二种方法,使用二条SQL语句来完成读取表单与用户信息

在读取order关联时 association 节使用了 select="getUserById" 属性,它表示使用 getUserById 这个SQL来读取用户信息。

 1 <resultMap type="cn.xleos.mybatis.po.Order" id="orderMap">
 2     <id property="id" column="id" />
 3     <result property="createtime" column="createtime" />
 4     <result property="number" column="number" />
 5     <result property="note" column="note" />
 6     <association property="user" column="user_id"
 7         javaType="cn.xleos.mybatis.po.User" select="getUserById" />
 8 </resultMap>
 9 <select id="getOrders" resultMap="orderMap">
10     SELECT id, user_id, number, createtime, note, FROM orders
11 <select>
12 <select id="getUserById" parameterMap="int" resultType="cn.xleos.mybatis.po.User">
13     SELECT id, username, birthday, sex, address FROM user where id = #{value}
14 <select>

通过日志可以发生在读取 order 数据时,就同时发送了2条SQL语句至数据库,读取 order 与 user 数据。

第三种方法,使用延时加载来访问 getUser() 时使用SQL语句读取user信息

1、需要在全局配置文件中添加lazyLoadingEnabled=true;
2、在关联映射(association)中设置 fetchType="lazy" 属性;
3、其它均与第二种方法一致;

1 <resultMap type="cn.xleos.mybatis.po.Order" id="orderMap">
2     <!-- 省略其它属性映射 -->
3     <association property="user" column="user_id"
4         javaType="cn.xleos.mybatis.po.User" select="getUserById" fetchType="lazy" />
5 </resultMap>

使用了延时加载后,在读取 order 表单时仅发送一个SQL语句,于数据库查询出 order 对象; 在访问 order.getUser() 时,再发送一条SQL至数据库,读取出 user 记录;

 

 

 

九、Mybatis代码生成器

十、mybatis日志_log4j

基础复习9-mybatis

这里要把用到的类都加进去

log4j.logger.com.wan.mapper.IUserMapper=TRACE
log4j.logger.mapperTest.IUserMapperTest=TRACE

# Global logging configuration

log4j.rootLogger=ERROR, stdout, FILE, log, INFO

# MyBatis logging configuration...

log4j.logger.com.wan.mapper.IUserMapper=TRACE

log4j.logger.mapperTest.IUserMapperTest=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



#FILE#

log4j.appender.FILE=org.apache.log4j.FileAppender

log4j.appender.FILE.Append=false

log4j.appender.FILE.ImmediateFlush=true

log4j.appender.FILE.File=log/log.log

log4j.appender.FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.FILE.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [ %t ]  %m%n

#LOG#

log4j.appender.log=org.apache.log4j.DailyRollingFileAppender

log4j.appender.log.FILE=log/log.log

log4j.appender.log.Append=true

log4j.appender.log.Threshold=INFO

log4j.appender.log.DatePattern='.'yyyy-MM-dd

log4j.appender.log.layout=org.apache.log4j.PatternLayout

log4j.appender.log.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [ %t ]  %m%n

#INFO#

log4j.appender.INFO=org.apache.log4j.DailyRollingFileAppender

log4j.appender.INFO.FILE=log/log.log

log4j.appender.INFO.Append=true

log4j.appender.INFO.Threshold=INFO

log4j.appender.INFO.DatePattern='.'yyyy-MM-dd

log4j.appender.INFO.layout=org.apache.log4j.PatternLayout

log4j.appender.INFO.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [ %t ]  %m%n

十一、Mybatis缓存(Mybatis提供两个级别的缓存(查询缓存))

基础复习9-mybatis

一级缓存:sqlSession级别:

在第一次查询时将从数据库获取的数据缓存到临时的内存空间中

以后每一次查询重复数据时不会再访问数据库,而是直接从缓存中获取,减少了对于数据库

      IO操作,从而提高访问效率,该级别缓存默认开,如果有提交事务时,该级别缓存会被清空,

如果sqlSession被关闭,该级别缓存也会随之消失。session.commit()事务提交也会清除缓存

二级缓存:Mapper级别缓存:

该级别缓存不会因为sqlsession的关闭而清空,被缓存的数据依然存储在

      Mapper级别,下一次重新获取sqlSession对象时还能使用该缓存区域的缓存数据;二级缓存需要(例如session.clearCache()清空缓存,再重新session = factory.openSession(); mapper = session.getMapper(UserMapper.class);   之前的缓存记录还在,针对于二级缓存)

配置:

             1.在Mapper文件中配置<cache/>

          2.缓存的对象所指代类必须实现序列化接口Serializable

<mapper namespace="com.softeem.mapper.UserMapper" >

  <cache   eviction="FIFO"        flushInterval="60000"

              size="512"            readOnly="true"/>

eviction:回收策略(LUR,FIFO)

flushInterval:刷新间隔数(毫秒)

size:缓存的引用对象数目

readOnly:是否设置为只读缓存

 

十二、mybatis注意事项

servlet存在并发问题,所以不要设属性。

SessionFactoryBuilder用一次new一次,范围为方法内;

SessionFactory范围为单例,session每次用都重新new。

 

Service类:

基础复习9-mybatis

Utils类:

基础复习9-mybatis