MyBatis复习

MyBaties框架简介

Mybatis本来是apache的一个开源项目,原名ibatis2010年该项目有apache software foundation迁移到google code,并改名为mybatis

Mybatis是一个优秀的持久层框架,用简单的xml和注解用于配置和原始映射。用接口和javapojo映射成数据库中的记录。

 

注:常用的持久层技术

    1jdbc

    2hibernate---ORM

    3mybatis----sql提取到xml配置文件、动态sql、缓存,原名为Ibatis

    4DBUtils

5JdbcTemplate

 

 

MyBaties框架jar

    mybatis-3.1.1.jar----核心包

    asm-3.3.1.jar

cglib-2.2.2.jar

commons-logging-1.1.1.jar

log4j-1.2.16.jar

slf4j-api-1.6.2.jar

slf4j-log4j12-1.6.2.jar

 

入门Demo

 

 

sqlMapConfig.xml

<?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>

     

     <!-- 为类定义别名

     <typeAliases>

<typeAlias type="com.mybatis.domain.User" alias="User"/>

</typeAliases> -->

<environments default="mysqlEnvironment">

<environment id="mysqlEnvironment">

    <!-- 事务管理器 -->

<transactionManager type="JDBC" />

<!-- 配置数据源,pooledmybaties提供的数据源 -->

<dataSource type="POOLED">

<property name="driver" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql:///mybatis" />

<!-- 

<property name="username" value="xxx"/>

<property name="password" value="xxx"/> 

-->

</dataSource>

</environment>

</environments>

<!-- 注册mybatissql映射文件 -->

<mappers>

    <!-- 包装了程序中要执行的sql语句 -->

<mapper resource="com/mybatis/domain/UserMapper.xml" />

</mappers>

</configuration>

UserMapper.xml

 

<?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">

 

<!-- namespace没有固定要求,但每一个mappernamespace必须唯一 -->

<mapper namespace="com.mybatis.domain.User">

    

   <sql id="allColumn">

        id,name,address

   </sql>

    

   <!-- 当前sql的一个唯一标识,java程序中根据id进行调用

   <insert id="" parameterType="">

      

   </insert>

   <delete id=""></delete>

   <update id=""></update> -->

   <select id="selectUserById" parameterType="int" resultType="com.mybatis.domain.User">

         select 

<include refid="allColumn"/>

 from mb_user where id = #{id}   <!-- #{id} 固定写法,类似于jdbc中的 ? -->

   </select>

</mapper>

 

关于mybatis的几点说明

1)为了更加直观的看到mybatis执行的sql语句,可以在项目的src目录下加入log4j.properties文件,将程序执行的sql输出到控制台

2)当数据表中的字段和对应的实体类中的属性不完全对应时,可以使用resultMap标签进行字段和属性的对应,这点和hibernate非常类似

 

<!-- entity - database field mapping --> 

   <resultMap type="com.mybatis.domain.Book" id="bookMap">

       <!-- 描述属性和字段的对应关系 -->

       <id column="id" property="id"/>  <!-- id  主键 -->

       <!-- 普通字段 -->

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

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

   </resultMap>

 

 

3)Sql映射文件中的parameterTyperesultType都可以指定为hashmap类型

   <!-- hashmap = java.util.HashMap  , int = java.lang.Integer -->

   <select id="selectBookById4Map" parameterType="int" resultMap="hashmap">      

         select * from mb_book where id = #{id}

   </select>

 

<insert id="insertBook2Map" parameterType="hashmap">

          insert into mb_book values (#{id},#{name},#{bookPrice})

</insert>

 

4)在sqlMapConfig.xml文件中可以定义别名,来简化开发

 <!-- 为类定义别名-->

     <typeAliases>

<typeAlias type="com.mybatis.domain.User" alias="User"/>

</typeAliases> 

5)利用<sql/>标签提取sql语句中的公共字段

   <sql id="allColumn">

        id,name,address

   </sql>

   <select id="selectUserById" parameterType="int" resultType="User">

         select 

<include refid="allColumn"/>

 from mb_user where id = #{id}   <!-- #{id} 固定写法,类似于jdbc中的 ? -->

   </select>

 

6)模糊查询

   <select id="selectUserByNameLike" parameterType="hashmap" resultType="User">

          select <include refid="allColumn"/> from mb_user

          where name like '%${name}%'

   </select>

   <select id="selectUserByNameLike1" parameterType="User" resultType="User">

          select <include refid="allColumn"/> from mb_user

          where name like '%${name}%'

   </select>

 

   注:或为实体类 或 为 map (keyname)

       当parameterType为基本类型是 #{p} 大括号中的内容可以随便写,此时其为一个普通占位符,

       若parameterType为引用类型时,#{p}大括号中的内容必须与引用类型中的字段相符,并且在应用类型中提供对应的gettersetter方法。

 

关联查询

配置文件及sql的写法:

客户与订单-一个客户对应多个订单

 

在客户方描述关系:

    private Integer id;

 private String name;

 private Integer age;

 private Set<Order> orders = new HashSet<Order>();

<resultMap type="Customer" id="costomerMap">

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

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

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

       <!-- field : Set<Order> orders -->

       <collection property="orders" ofType="Order">

           <!-- user alias name for id in order, if not , c.id is same as o.id, 

             there will be probloms   -->

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

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

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

       </collection>

   </resultMap>

   <select id="selectCustomerOrderById" parameterType="int" 

                                                       resultMap="costomerMap">

       

       select c.id,c.name,c.age,o.id as   

                    oid,o.orderNumber,o.price,o.customerId 

       from 

       itheima_customer c

         left join itheima_order o

         on c.id = o.customerId

   where c.id = #{id}

       

   </select>

       

 

 

 

 

从订单方描述关联关系:

   private Integer id;

private String orderNumber;

private Double price;

private Customer customer;

      <resultMap type="Order" id="orderMap">

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

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

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

           <association property="customer" javaType="Customer">

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

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

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

           </association>

       </resultMap>

       <select id="selectOrderById" parameterType="int" resultMap="orderMap">

             select o.id,o.orderNumber,o.price,o.customerId,c.id as 

                     cid,c.name,c.age

             from itheima_order o

                left join itheima_customer c

                on o.id = c.id

             where o.id = #{id}           

       </select>

 

动态sql查询与更新

<!-- dynamic select -->

   <select id="selectBookByCondition" parameterType="Book" resultMap="bookMap">

          select id,name,bookPrice from mb_book where 1 = 1

          <if test="id != null">

             and id = #{id}

          </if>

          <if test="name != null">

             and name = #{name}

          </if>

          <if test="price != null">

             and bookPrice = #{price}

          </if>

   </select>

   <select id="selectBookByCondition2" parameterType="Book" resultMap="bookMap">

          select id,name,bookPrice from mb_book

          <where>

               <if test="id != null">

              and id = #{id}

           </if>

           <if test="name != null">

              and name = #{name}

           </if>

           <if test="price != null">

              and bookPrice = #{price}

           </if>

          </where>

   </select>

   <!-- dynamic update -->

   <update id="updateBookByCondition" parameterType="Book">

          update mb_book 

          <set>

             <if test="name != null">

                 name = #{name}

             </if>              

          </set>

          <where>

             <if test="id != null">

                 id = #{id}

             </if>

          </where>

   </update>

 

批量插入与批量查询

<!-- batch insert -->

   <insert id="batchInsertUsers" parameterType="hashmap">

          insert into mb_user (name,address) values 

          <foreach collection="users" item="var" separator=",">

              (#{var.name},#{var.address})

          </foreach>

   </insert>

 

         时SqlSession session = sessionFactory.openSession();

Map<String,List<User>> users = new HashMap<String,List<User>>();

User user1 = new User("wangwu","changchun");

User user2 = new User("zhaoliu","tianjin");

List<User> user = new ArrayList<User>();

user.add(user1);

user.add(user2);

users.put("users", user);

int result = session.insert("com.mybatis.domain.User.batchInsertUsers", users);

session.commit();

   <!-- batch select -->

   <select id="batchSelectUsers" parameterType="map" resultMap="userMap">

          select u.id, u.name, u.address from mb_user u

          <if test="ids.size > 0">

          <where>

             id in

             <foreach collection="ids" item="id" separator="," open="(" 

                                                                             close=")">

                  #{id}                 

             </foreach>

          </where>

          </if>

   </select>

         SqlSession session = sessionFactory.openSession();

Map<String,List<Integer>> ids = new HashMap<String,List<Integer>>();

List<Integer> idList = new ArrayList<Integer>();

//idList.add(1);

//idList.add(2);

//idList.add(3);

ids.put("ids", idList);

List<User> users =   

         session.selectList("com.mybatis.domain.User.batchSelectUsers", ids);

 

Spring整合myBatis

spring整合mybatis

1)创建一个java项目

2)加入jar

aopalliance-1.0.jar

commons-logging-1.1.1.jar

mybatis-3.0.3.jar

mybatis-spring-1.0.0-RC3.jar

mysql-connector-java-5.1.5-bin.jar

spring-aop-3.0.5.RELEASE.jar

spring-asm-3.0.5.RELEASE.jar

spring-beans-3.0.5.RELEASE.jar

spring-context-3.0.5.RELEASE.jar

spring-core-3.0.5.RELEASE.jar

spring-expression-3.0.5.RELEASE.jar

spring-jdbc-3.0.5.RELEASE.jar

spring-tx-3.0.5.RELEASE.jar

3)提供mybatis框架的核心配置文件sqlMapConfig.xml

4)提供spring配置文件beans.xml(数据源、SqlSessionFactoryBean、事务管理器、通知、AOP切面)

5)创建数据库和表

6)创建实体类和SQL映射文件

7)提供Daoservice

 

applicationContext.xml

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

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:mvc="http://www.springframework.org/schema/mvc"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop" 

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="http://www.springframework.org/schema/beans 

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 

http://www.springframework.org/schema/mvc 

http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 

http://www.springframework.org/schema/context 

http://www.springframework.org/schema/context/spring-context-3.0.xsd 

http://www.springframework.org/schema/aop 

http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 

http://www.springframework.org/schema/tx 

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">

<!-- 数据源   DriverManagerDataSource不是连接池实现-->

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver"/>

<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>

<!--<property name="username" value="root"/>

<property name="password" value="root"/>

-->

</bean>

<!-- 配置spring整合mybatis的工厂bean -->

<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dataSource"/>

<property name="configLocation" value="classpath:sqlMapConfig.xml"/>

</bean>

<!-- 配置事务管理器 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

<!-- 通知 -->

<tx:advice id="mybatis_advice" transaction-manager="transactionManager">

<tx:attributes>

<tx:method name="save*" propagation="REQUIRED"/>

<tx:method name="delete*" propagation="REQUIRED"/>

<tx:method name="update*" propagation="REQUIRED"/>

<tx:method name="find*" read-only="true"/>

</tx:attributes>

</tx:advice>

<!-- AOP切面 -->

<aop:config>

<aop:pointcut expression="execution(* com.mybatis.service.*.*(..))" id="myBatis_pc"/>

<aop:advisor advice-ref="mybatis_advice" pointcut-ref="myBatis_pc"/>

</aop:config>

<!-- dao -->

<bean id="userDao" class="com.mybatis.dao.impl.UserDaoImpl">

     <property name="sqlSessionFactory" ref="sessionFactory"/>

</bean>

<!-- service -->

<bean id="userService" class="com.mybatis.service.impl.UserServiceImpl">

     <property name="userDao" ref="userDao"/>

</bean>

</beans>

 

sqlMapperConfig.xml

<?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>

     

     <!-- 为类定义别名-->

     <typeAliases>

<typeAlias type="com.mybatis.domain.User" alias="User"/>

</typeAliases> 

<!-- spring对数据源进行管理 -->

<!--<environments default="mysqlEnvironment">

<environment id="mysqlEnvironment">

     事务管理器 

<transactionManager type="JDBC" />

 配置数据源,pooledmybaties提供的数据源 

<dataSource type="POOLED">

<property name="driver" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql:///mybatis" />

 

<property name="username" value="xxx"/>

<property name="password" value="xxx"/> 

</dataSource>

</environment>

</environments>

-->

<!-- 注册mybatissql映射文件 -->

<mappers>

    <!-- 包装了程序中要执行的sql语句 -->

<mapper resource="com/mybatis/domain/UserMapper.xml" />

</mappers>

</configuration>

 

*核心:

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {

 

 

 

*log4j日志级别

Fatal:致命错误

Error:普通错误

Warn:警告

Info:信息(用的比较多)

Debug:调试信息

Trace:堆栈信息

 

MyBatis插件(略)

MyBatis一级缓存

框架的内置缓存,不用配置,默认存在,不能卸载,生命周期为session的生命周期。

在同一个session中,先后查询同一个数据,即sql语句完全相同,则数据会从mybatis缓存中取得,而不是去查询数据库。

*MyBatis一级缓存是对对应的引用进行缓存。

 

测试例子:

@Test

public void firstLevelCacheTest(){

SqlSession session = sessionFactory.openSession();

//发送sql

User user1 = 

         (User)session.selectOne("com.mybatis.domain.User.selectUserById",1);

//不发送sql

User user2 =

         (User)session.selectOne("com.mybatis.domain.User.selectUserById",1);

    System.out.println("user1 : " + user1);

    System.out.println("user2 : " + user2);

    System.out.println(user1 == user2);  // true

    session = sessionFactory.openSession();

    //发送sql

    User user3 =

        (User)session.selectOne("com.mybatis.domain.User.selectUserById",1);

    System.out.println(user3 == user2); //false

}

 

 

 

 

日志信息:

 Created connection 28309992.

11:16:51,326 DEBUG selectUserById:47 - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@1aff9e8]

11:16:51,326 DEBUG selectUserById:47 - ==>  Preparing: select id,name,address from mb_user where id = ? 

11:16:51,407 DEBUG selectUserById:47 - ==> Parameters: 1(Integer)

 

*两次查询只第一次向数据库发送sql语句。

 

MyBatis二级缓存

默认没有启用,

在核心配置文件中加入<setting name="cacheEnabled" value="true"/>

SQL映射文件中加入<cache/>

SQL语句中使用useCache = "true|false"

 

测试例子:

sqlMapConfig.xml

     <!-- two level cache config. main cache switch --> 

<settings>

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

</settings>

UserMapper.xml

   <!-- 当前mapper中的sql使用二级缓存 --> 

   <cache/> 

 

<!-- cache -->

   <select id="selectUserById" parameterType="int" resultType="User">

         select 

<include refid="allColumn"/>

 from mb_user where id = #{id}   <!-- #{id} 固定写法,类似于jdbc中的 ? -->

   </select>

   

   <!-- sql不使用二级缓存 -->

   <select id="selectUserByIdNoCache" parameterType="int" resultType="User" useCache="false">

         select 

<include refid="allColumn"/>

 from mb_user where id = #{id}   <!-- #{id} 固定写法,类似于jdbc中的 ? -->

   </select>

 

SqlSession session = sessionFactory.openSession();

//发送sql,放入一级缓存和二级缓存

User user1 = (User)session.selectOne("com.mybatis.domain.User.selectUserById",1);

//不发送sql,优先从一级缓存中取数据,

User user2 = (User)session.selectOne("com.mybatis.domain.User.selectUserById",1);

    session.close();

    session = sessionFactory.openSession();

    //发送sql,此时从二级缓存中取

    User user3 = (User)session.selectOne("com.mybatis.domain.User.selectUserById",1);

    //一级缓存是缓存对象的引用,二级缓存是缓存散装的数据,当cache hit时,用这些数据重新组装实体,然后返回

    System.out.println(user1 == user3);  //false

 

二级缓存说明

1)当在BeanMapper.xml中配置<cache/>时,默认所有sql都使用二级缓存,如果想将某个sql配置成不使用二级缓存可以在相应的sql标签中配置useCache=false

2)BeanMapper.xml中所有的inert/update/delete语句将默认刷新缓存,这三种sql标签中有

   flushCache=”true”默认情况下为true,即同一个sessionFactory当有sql语句更新时缓存自

   动刷新,以确保数据的实时性。如果改成false,则不会自动刷新。使用缓存时,如果手

   工修改数据库表中的数据则会出现脏读现象,缓存将使用LRU(Leasted Recently used)

   近最少使用策略算法来回收。

   <cache eviction=”FIFO” flashIntlevel=”60000”  readOnly=”true”>

   这个更高级的配置创建了一个FIFO缓存,并每隔60秒刷新,存储结果对象或列表的

   512个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改他

   们会导致冲突,默认的回收策略是LRU,可用的回收策略有:

   (1LRU:最近最少使用的-移除最长时间不被使用的对象。

   (2FIFO:按对象进入缓存的顺序来移除他们

   (3SOFT:移除基于垃圾回收器状态和软引用规则的对象。

   (4WEAK:若引用-更积极的移除基于垃圾回收器状态和弱引用规则的对象。

    

应用缓存时存在的问题

应用缓存时,可能会出现脏读现象,即当数据库中的数据被更新后,缓存中的数据没有进行同步,此时缓存中的数据就会与数据库中的数据不一致,当cache hit时,取出来的数据就会与数据库中的数据不一致。

 

一般情况下,只对不经常变换的且不太重要、出现少量偏差时可以接受的数据进行缓存处理,提供系统响应速度。

 

MyBatis配置ehcache

    *导入jar

mybatis-ehcache-1.0.2.jar

ehcache-core-2.6.5.jar

slf4j-api-1.6.1.jar

提供一个ehcache的配置文件ehcache.xml

SQL映射文件中加入<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

 

ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

    

    <!-- 系统临时目录, 或自行制定一个缓存路径 ,当缓存对象个数超过maxElementsInMemory时,会将其缓存到磁盘上-->

    <diskStore path="java.io.tmpdir"/>

    

    <defaultCache

            

            maxElementsInMemory="10"   

            eternal="false"

            timeToIdleSeconds="120"

            timeToLiveSeconds="120"

            maxElementsOnDisk="10000000"

            diskExpiryThreadIntervalSeconds="120"

            memoryStoreEvictionPolicy="LRU">

        <persistence strategy="localTempSwap"/>

    </defaultCache>

    <!-- 

            maxElementsInMemory : 内存中最大缓存对象数,ehcache会按制定的策略去清理内存

            eternal : 缓存对象是否永久有效,一旦设置改属性为true,则timeout失效

            timeToIdleSeconds : 设置elements在失效前的允许空闲时间,仅当elements不是永久有效时使用。是可选属性,

                                                                                                         默认值是0,也就是空闲时间可以是无限大。

                                                                                                         

            timeToLiveSeconds :  设置elements在失效前允许存活时间,最大时间介于创建时间和失效时间之间,  仅当elements

                                                                                                          为永久有效时,使用默认值0,也就是elements存活时间无线大

                                                                                                         

            maxElementsOnDisk :  磁盘中最大缓存对象数,0为无限大

            diskExpiryThreadIntervalSeconds : 磁盘失效线程运行时间间隔  。

            memoryStoreEvictionPolicy : 当maxElementsInMemory限制时,ehcache将根据指定的策略去清理内存,

                                                                                                                                                                                          

     -->

</ehcache>

 

BeanMapper.xml

<!-- 将二级缓存设置为ehcache -->

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值