zoukankan      html  css  js  c++  java
  • MyBatis:动态SQL语句 (1)Xml方式 (2)注解方式 ,MyBatis的缓存,MyBatis的关联查询 ,MyBatis逆向工程

    动态SQL语句

    动态SQL是什么:

    就是相对与固定SQL。就是通过传入的参数不一样,可以组成不同结构的SQL语句. 这种根据参数的条件修改SQL结构的SQL语句,我们称为动态SQL语句.

    动态SQL有什么用

    1.根据条件组装不同结构的SQL语句,可以提高SQL代码的重用性.

    2.满足某些特定需求,如,条件判断查询

    基于XML的实现

    标签包括

    <sql>  用于声明公有的SQL语句块.,在操作标签中使用<include>调用 [不建议用]

    不建议的原因,会导致代码难以维护。

    <if>  类似java if(){},用于判断

    <foreach>:类似javaforeach循环,一般用户批量处理的SQL语句

    <trim> :切割标签,主要用于切割关键字的头和尾的字符.新版的Mybatis使用的几率很少.

    <set>:使用 set标签就是SQL语言的set关键字,可以在update 的时候set 关键字后面的,逗号可以自动忽略

    <where>:使用where标签作为SQL语言的where关键字,好处如果where后面的条件都不成立,忽略where关键字.

    <choose> <when> <otherwise> :  javaswithc case

    
    
    <?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="cn.zj.mybatis.mapper.UserMapper">
        <!-- 抽取一个sql片段 <sql id="sql片段的唯一标识"></sql> -->
        <sql id="condition_sql">
            <!-- 动态SQL语句之 where 标签 ,内部具体条件 -->
            <where>
                <!-- 条件 <if test="">标签体内容</test> test :内部是一个布尔类型的结果, 如果为true 标签体中内容生效,如果为false,标签内容无效 
                    concat ():串联起来括号内 -->
                <if test="username !=null">username like concat('%',#{username},'%') </if>
                <if test="age !=null">and age = #{age}</if>
    
            </where>
        </sql>
    
    
    
        <!-- 根据条件查询 -->
        <select id="selectList" parameterType="user" resultType="user">
            <!-- 静态sql语句:语义固定 -->
            <!-- select * from user where name like concat('%',#{name},'%') and age 
                = #{age} -->
            select * from user
    
            <!-- 引入sql片段 <include refid="condition_sql"/> refid:对应sql片段的id -->
            <include refid="condition_sql" />
    
    
        </select>
    
    
        <select id="selectTotalByCondition" parameterType="user"
            resultType="long">
    
            select count(*) from user
            <include refid="condition_sql" />
        </select>
    
    </mapper>
    
    
    


    package
    cn.zj.mybatis.test; import static org.junit.Assert.*; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import cn.zj.mybatis.mapper.UserMapper; import cn.zj.mybatis.pojo.User; import cn.zj.mybatis.util.MyBatisUtil; public class UserMapperTest { @Test public void testName() throws Exception { SqlSession openSession = MyBatisUtil.openSession(); UserMapper mapper = openSession.getMapper(UserMapper.class); User user=new User(); //user.setUsername("e"); user.setAge(20); List<User> selectList = mapper.selectList(user); long selectTotalByCondition = mapper.selectTotalByCondition(user); System.out.println("總數"+selectTotalByCondition); openSession.close(); }}
    
    
    <?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="cn.zj.mybatis.mapper.UserMapper">
    
        <!-- 修改用户信息 -->
        <update id="updateUserInfo" parameterType="user">
            <!-- 静态sql语句:固定语义 -->
            <!-- update user set name = #{name},password=#{password},age = #{age} where 
                id = #{id} -->
            update user
            <!-- 动态sql语句 set标签 -->
            <set>
            <if test="username !=null">username = #{username},</if>
            <if test="password !=null">password =#{password},</if>
            <if test="age !=null">age =#{age}</if>
            </set>
    
            where id =#{id}
    
    
    
    
        </update>
    
    
    </mapper>
    
    
    


    @Test
    public void testUpdata() throws Exception { SqlSession openSession = MyBatisUtil.openSession(); UserMapper mapper = openSession.getMapper(UserMapper.class); User user = new User(); user.setId(5); user.setPassword("小明"); int updateUserInfo = mapper.updateUserInfo(user); openSession.commit(); openSession.close(); }

     

    package cn.zj.mybatis.test;
    
    import static org.junit.Assert.*;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import cn.zj.mybatis.mapper.UserMapper;
    import cn.zj.mybatis.pojo.User;
    import cn.zj.mybatis.util.MyBatisUtil;
    
    public class UserMapperTest {
    
    
        @Test
        public void testInsertUserInfo() {
            // 1.创建SqlSession会话对象
            SqlSession session = MyBatisUtil.openSession();
            // 2.创建UserMapper接口的代理对象(Java的动态代理)
            UserMapper mapper = session.getMapper(UserMapper.class);
            User user1 = new User(null, "xireejhef", "wffew", 10);
            User user2 = new User(null, "xijfdhxhef", "wffew", 10);
            User user3 = new User(null, "xijdfhhhef", "wffew", 10);
            List<User> user=Arrays.asList(user1,user2,user3);
            // 3.执行插入方法
            int row = mapper.insertUserInfo(user);
            // 4.提交事务(Mybatis默认DML操作需要手动提交事务)
            System.out.println(row);
            session.commit();
            // 5.关闭session
            session.close();
    
        }
      <insert id="insertUserInfo" parameterType="user">
         <!-- insert into user (name,password,age)values('张三','zs',18),('李四','ls',20) -->
            <!-- ('张三','zs',18),('李四','ls',20) -->
        insert into user (username,password,age)values
        <foreach collection="users" item="user" separator=",">
        (#{user.username},#{user.password},#{user.age})
        </foreach>
        </insert>
    
    
    
    
        @Test
        public void testDelet() {
            SqlSession openSession = MyBatisUtil.openSession();
            UserMapper userMapper = openSession.getMapper(UserMapper.class);
            Integer[] id= {4,5};
            int user = userMapper.deleteByPrimaryKey(id);
    
            System.out.println(user);
            openSession.commit();
            openSession.close();
    
        }
        <!-- 批量删除 -->
    
        <delete id="deleteByPrimaryKey" parameterType="int">
       
       delete from user where id in
            <foreach collection="ide" item="id" open="(" close=")"
                separator=",">
                #{id}
            </foreach>
        
        
        </delete>
    
      
    
    
    
    
    
    
        @Test
        public void testSelectList() throws Exception {
            SqlSession openSession = MyBatisUtil.openSession();
            UserMapper mapper = openSession.getMapper(UserMapper.class);
            Integer[] id= {1,3};
            List<User> selectList = mapper.selectList(id);
            for (User user : selectList) {
                
            System.out.println(user);
            }
            openSession.close();
        }
    }
        <!-- 批量查询 -->
        <select id="selectList" parameterType="int" resultType="user">
            <!-- sql :select * from user where id in(1,2,3,4) 问题: 要动态拼接的sql : (1,2,3,4) 
                答: 使用 foreach 标签 <foreach collection="" item="" open="" close="" separator="">标签体</foreach> 
                collection:需要循环的数组或者集合 item :每次循环出的数据赋值的变量,在标签体中使用 open : 循环开始的 圆括号 ( close 
                :循环结束的圆括号) separator :每次循环的分隔符 逗号 《 -->
    
            select * from user where id in
            <foreach collection="ids" item="id" open="(" close=")"
                separator=",">
                #{id}
            </foreach>
    
        </select>
        
        
    
    
    
     

    基于注解方式实现

    动态sql除了支持xml方式以外,还是支持使用纯注解的方式

    主要一下四个注解+对应动态sql语句的类文件

    1. @SelectProvider  动态查询SQL语句对应注解
    2. @InsertProvider  动态插入SQL语句对应注解
    3. @UpdateProvider  动态修改SQL语句对应注解
    4. @DeleteProvider  动态删除SQL语句对应注解

     

    
    
    package cn.zj.mybatis.pojo;
    
    /*
     * 此类是专门编写 User表对应的动态SQL语句的类
     */
    public class UserProvide {
    
        /*
         * 拼接动态sql语句的方法 注意:内部的 参数使用还是使用 OGNL 表达式
         */
        public String selectByCondition(User user) {
            StringBuilder str = new StringBuilder();
            str.append("select * from user WHERE 1 = 1");
            // 拼接动态sql
            if (user.getUsername() != null) {
                str.append(" and username like concat('%',#{username},'%')");
            }
            if (user.getAge() != null) {
                str.append(" and age = #{age}");
            }
            
            return str.toString();
            
        }
        
        public String selectTotalByCondition(User user) {
            StringBuilder str = new StringBuilder();
            str.append("select count(*) from user WHERE 1 = 1");
            // 拼接动态sql
            if (user.getUsername() != null) {
                str.append(" and username like concat('%',#{username},'%')");
            }
            if (user.getAge() != null) {
                str.append(" and age = #{age}");
            }
            
            return str.toString();
        }
        
    
        
    }
    
    
    

    package
    cn.zj.mybatis.test;
        /**
         * 单行查询
         * @param id 主键id
         * @return  查询结果封装的User对象
         */
        /*
         * 查询动态sql语句的注解
         * @SelectProvider(type=cn.zj.mybatis.pojo.UserProvider.class,method="")
         * 属性
         *     type :拼接动态sql语句的类
         *  method :返回具体动态sql语句的方法名称
         *             注意 :方法的参数类型个数,必须和功能方法的参数类型个数一模一样(规则)
         *          建议:返回动态sql语句方法的名称和 当前功能的方法名称一样
         */
        @SelectProvider(type=UserProvide.class,method="selectByCondition")
        List<User> selectTotalByCondition(User user);
        /**
         * 根据提交查询总数
         * @param user
         * @return
         */
        
        @SelectProvider(type=UserProvide.class,method="selectTotalByCondition")
        Long selectCondition(User user);
        
    
    
    
    import static org.junit.Assert.*;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import cn.zj.mybatis.mapper.UserMapper;
    import cn.zj.mybatis.pojo.User;
    import cn.zj.mybatis.util.MyBatisUtil;
    
    public class UserMapperTest {
    
    
        @Test
        public void testSelectList() throws Exception {
        //查詢
            SqlSession openSession = MyBatisUtil.openSession();
            UserMapper mapper = openSession.getMapper(UserMapper.class);
            User users = new User();
            users.setAge(10);
            users.setUsername("1");
            mapper.selectTotalByCondition(users);
            mapper.selectCondition(users);
            openSession.close();
        }
    }
    
    
    package cn.zj.mybatis.pojo;
    
    /*
     * 此类是专门编写 User表对应的动态SQL语句的类
     */
    public class UserProvide {
    
        
        public String updateUserInfoa(User user) {
        StringBuilder str = new    StringBuilder();
        str.append("update user set ");
        if (user.getAge() !=null) {
            str.append("age =#{age},");
        }
        if (user.getUsername() !=null) {
            str.append("username =#{username},");
        }
        if (user.getPassword() !=null) {
            str.append("password =#{password},");
        }
        // 删除最后一个逗号
        str.deleteCharAt(str.length()-1);
        str.append(" where id =#{id}");
        return str.toString(); 
        }
        
        
        
        
        
        
    }
    
    
    
     
    @UpdateProvider(type=UserProvide.class,method="updateUserInfoa")
        int updateUserInfo(User user);
    
    
    

    @Test
    public void testupdate() { //修改 SqlSession openSession = MyBatisUtil.openSession(); UserMapper userMapper = openSession.getMapper(UserMapper.class); User user = new User(); user.setId(6); user.setUsername("mmmmmmmm"); user.setAge(100); user.setPassword("abcabc"); int user1 = userMapper.updateUserInfo(user); System.out.println(user1); openSession.commit(); openSession.close(); }
    package cn.zj.mybatis.pojo;
    
    import org.apache.ibatis.annotations.Param;
    
    /*
     * 此类是专门编写 User表对应的动态SQL语句的类
     */
    public class UserProvide {
    
        public String deleteByPrimaryKeya(@Param("ide")Integer[] ide) {
        StringBuilder sb = new    StringBuilder();
        sb.append("delete from user where id in (");
        for (int i = 0; i < ide.length; i++) {
            sb.append("#{ide["+i+"]},");
        }
        sb.deleteCharAt(sb.length()-1);
        sb.append(")");
        
            return sb.toString();
            
        }
        
        
        
        
        
        
    }
    @DeleteProvider(type=UserProvide.class,method="deleteByPrimaryKeya")
        int deleteByPrimaryKey(@Param("ide")Integer[] ide);
        
    
    
    

    @Test
    public void testDelet() { //删除 SqlSession openSession = MyBatisUtil.openSession(); UserMapper userMapper = openSession.getMapper(UserMapper.class); Integer[] id= {6,7}; int user = userMapper.deleteByPrimaryKey(id); System.out.println(user); openSession.commit(); openSession.close(); }
      
    package cn.zj.mybatis.pojo;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    /*
     * 此类是专门编写 User表对应的动态SQL语句的类
     */
    public class UserProvide {
    
        public String insertUserInfo(@Param("users")List<User> users) {
        StringBuilder sb = new    StringBuilder();
        sb.append("insert into user(Username,password,age) values ");
        for (int i = 0; i <users.size(); i++) {
            sb.append("(#{users[" + i + "].username},#{users[" + i + "].password},#{users[" + i + "].age}),");
        }
        sb.deleteCharAt(sb.length()-1);
        
        
            return sb.toString();
            
        }
        
        
        
        
        
        
    }
    
    
    


          
        /**
         * 批量插入
         * @param users
         * @return
         */
        @InsertProvider(type=UserProvide.class,method="insertUserInfo")
        int insertUserInfo(@Param("users")List<User> users);
        
    
    
    

    @Test
    public void testInsertUserInfo() { // 1.创建SqlSession会话对象 SqlSession session = MyBatisUtil.openSession(); // 2.创建UserMapper接口的代理对象(Java的动态代理) UserMapper mapper = session.getMapper(UserMapper.class); User user1 = new User(null, "xireejhef", "wffew", 10); User user2 = new User(null, "xijfdhxhef", "wffew", 10); User user3 = new User(null, "xijdfhhhef", "wffew", 10); List<User> user=Arrays.asList(user1,user2,user3); // 3.执行插入方法 int row = mapper.insertUserInfo(user); // 4.提交事务(Mybatis默认DML操作需要手动提交事务) System.out.println(row); session.commit(); // 5.关闭session session.close();

     缓存

    Mybatis里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录.从而提高查询的效率.

    缓存作用

    提高查询的效率.

     一级缓存

    Mybatis的缓存分为一级缓存 二级缓存

    一级缓存:所谓的一级缓存就是会话(SqlSesion对象)级别的缓存,就是同一个会话,如果已经查询过的数据会保存一份在内存中,如果会话没有关闭,再次调用同样的方法查询,不会再查询数据库,而是直接从缓存中取出之前查询的数据.

    一级缓存默认是打开的,而且是关闭不了的.

    如何清空一级缓存.

    1.关闭会话.close()

    2.进行了操作(增删改),提交了commit();

    3.手工清除缓存clearCache()

    二级缓存

    一级缓存是SqlSession对象级别,在每一次会话中有效

    二级缓存是 SqlSessionFactory级别,在整个应用都有效,可以在多个会话有效

    MyBatis本身并没有实现二级缓存

    二级缓存需要第三方缓存提供商的支持

    Ehcache -第三方缓存(Hibernate框架默认就是支持)

    学习地址

    http://www.mybatis.org/ehcache-cache/

    下载ehcache

    https://github.com/mybatis/ehcache-cache/releases

    配置开启二级缓存

    MyBatis开启二级缓存新版本已经默认支持开启二级缓存.可以不改

    <settings>

    <!-- 开启二级缓存 -->

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

    </settings>

    1.导包

    2.配置文件

    缓存的xml

    <ehcache>
        <!-- 缓存的磁盘位置 -->
        <diskStore path="D:/mybatis_cache"/>
        <!-- 默认的缓存策略: 如果开发者在某一个需要缓存的文件配置了自定义缓存,就不使用默认的,如果没有配置,就使用默认缓存策略-->
        
        <!-- 
            maxElementsInMemory="10000" 内存最大缓存的对象个数
            eternal="false" 是否是永久有效
            timeToIdleSeconds="120"  最大缓存时长
            timeToLiveSeconds="120"  最大有效时长
            overflowToDisk="true"  超出内存个数以后是否缓存到磁盘
        
         -->
        <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
          />
    </ehcache>

    缓存日志的properties文件

    # Global logging configuration
    log4j.rootLogger=ERROR, stdout
    # MyBatis logging configuration...
    log4j.logger.cn.zj.mybatis.mapper=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

    在映射文件中配置<cache>以及配置对应的缓存策略

    <mapper namespace="cn.zj.mybatis.dao.UserMapper">
        
        <!-- 当前表的映射开启支持二级缓存,并设置相关的缓存提供商,以及缓存的相关配置 -->
        <cache type="org.mybatis.caches.ehcache.EhcacheCache" >
           <!--最大的空闲时间  -->
           <property name="timeToIdleSeconds" value="10000"/>
           <!-- 最大的在线时间 -->
           <property name="timeToLiveSeconds" value="20000"/>
           <!-- 内存的大小 b字节 m1 =1024k 1k=1024b -->
           <property name="maxEntriesLocalHeap" value="2000000"/>
           <!-- 文件的大小 b字节-->
           <property name="maxEntriesLocalDisk" value="20000000"/>
           <!-- 算法 LRU:最少使用优先, "LFU" or "FIFO:先进先出 -->
           <property name="memoryStoreEvictionPolicy" value="LRU"/>
        </cache> 
        <select id="selectAll" resultType="User">
            select * from user
        </select>
    </mapper>

     在对象类中序列化

    因为二级缓存可以缓存到文件(将对象序列化到本地),涉及到对象序列化,那么对应的javaBean对象就必须实现 

     

    缓存的命中率

    命中率= 从缓存中获取数据的次数/ 查询的总次数

    : 两次查询 从缓中获取一次

    0.5 =  1/2;

    0.666666 = 2/3;

    命中率越高缓存效果越好

     MyBatis的对象关系映射(难点重点)

    在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值连接), 等值连接 表与表之间有一个外键关键

    但是程序中最终获取的表封装的对象, 对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系

    对象之间关系主要是四种

    一对一 关系
    一个人对应身份证id,一个QQ号对应一个QQ空间

    一对多 关系

        一个部门对应多个员工

    多对一 关系

       多个员工对应一个部门

    多对多 关系

       多个学生对应多个老师,多个学生对应多个课程

    什么关系应该从哪个对象作为中心点来看

    一对多, one方作为中心点

    MyBatis框架支持多表查询封装对象之间关系

    <collection> 一对多查询

    <association>多对一和一对一查询

    多对1,以age为外键

     

     

    一对多

    <?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="cn.zj.mybatis.mapper.UserMapper">
        <select id="testSelect" resultMap="use">
            select * from user2 where age =#{age}
        </select>
        <!-- 手动映射 -->
        <resultMap type="cn.zj.mybatis.pojo.User2" id="use">
        
        
        <result column="name" property="name"/>
        
        <!-- 
                  问题: private User user; 部门对象如何映射?
                   
                   解决方案:使用 联合查询标签
                    <collection property="" column="" select=""/>
                    property :需要映射的pojo对象的属性此时就是  dept
                    column :已知对应dept对象的外键列
                    select :需要去查询的功能id
               -->
               <collection property="user" column="age" select="findByDeptId"/> 
        
        </resultMap>
    
    <!-- 联合查询的功能 -->
          
          <!-- 根据部门的id查询出对应的部门对象-->
          <select id="findByDeptId" parameterType="Integer" resultType="cn.zj.mybatis.pojo.User">
          
          select * from user where age = #{age}
          </select>
    </mapper>

    结果:

    等值连接查询(1对多,其他和上面一样)

    <?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="cn.zj.mybatis.mapper.UserMapper">
        <select id="testSelect" resultMap="use">
            select u.id u_id ,u.password u_password,u.username u_username,s.age s_age,s.name s_name
             from user u,user2 s where u.age =s.age and s.age=#{age}
        </select>
        <!-- 手动映射 -->
        <resultMap type="cn.zj.mybatis.pojo.User2" id="use">
        
        <id column="s_age" property="age"/>
        <result column="s_name" property="name"/>
        <!-- 
                  问题: private List<User> user; 员工集合如何映射?
                  解决方案:使用 <collection>集合标签,在内部映射多方(员工)的信息
                  <collection property="" column="" select=""/>    
                  property :需要映射的属性 此时就是 user
                  ofType:需要映射集合user 的泛型
               -->
               <collection property="user" ofType="cn.zj.mybatis.pojo.User"> 
        <id column="u_id" property="id"/>
        <result column="u_username" property="username"/>
        <result column="u_password" property="password"/>
        <result column="u_age" property="age"/>
        </collection>
        </resultMap>
    
    
    </mapper>

    MyBatis的逆向工程

    MyBatis的逆向工程能自动帮开发者生成数据库表对应的 pojo实体文件,自动生成映射文件

    自定生成表的各种(CRUD)sql语句, 但是只能做单表操作,联合查询还得开发者自己动

    使用逆向工程得先在Eclipse安装逆向工程的插件

    1.安装插件

    2.新建一个普通java项目,导入mybatis.jar包和数据库驱动包

    3.

  • 相关阅读:
    时间戳
    MD5加密、字节与字符串转换、对ToString("X2 ")的理解
    JWT(JSON Web Token)简介
    Entity Framework 通过主键查询提高效率
    C# switch语句与枚举类型
    对象映射库【AutoMapper】所支持场景
    关于EF框架EntityState的几种状态
    EF底层操作注意点、批量操作、更新
    linq:求分组后的每组最大值、最小值、平均值等、Aggregate聚合函数
    Flask——Request(2)
  • 原文地址:https://www.cnblogs.com/406070989senlin/p/11124536.html
Copyright © 2011-2022 走看看