Mybatis简单实用

1.全局配置
    <properties></properties> 引入外部*.ptoperties文件,可以通过${jdbc.ulr}区出properties中的值
     <settings>
        <setting name="" value=""/>定义mybatis的一些全局性设置,在官网可以查看具体设置哪些
        <setting name="mapUnderscoreToCamelCase" value="false"/>设置是否开启下划线命名法转驼峰命名法
     </settings> 
     <typeAliases></typeAliases> 为一些类定义别名
     <typeHandlers></typeHandlers> 类型处理器:定义Java类型与数据库中的数据类型之间的转换关系
     <objectFactory type=""></objectFactory> 对象工厂
     <plugins>  插件:mybatis的插件,插件可以修改mybatis的内部运行规则
        <plugin interceptor=""></plugin>
     </plugins> 
2.mapper映射文件
 
  1. 增删改查
  2. <mapper namespace="com.njupt.mapper.StudentMapper"> <!-- 接口全类名 -->
             <!-- resultType 可以省略 -->
            <select id="getStudentById"  resultType="com.njupt.entities.Student">
                   select * from student where id=#{id}
            </select>
              <!-- resultType 可以省略 -->
            <insert id="addStudent"  parameterType="com.njupt.entities.Student">
                   insert into student(name,age) values(#{name},#{age})
            </insert>
            <!-- resultType 可以省略 -->
            <update id="updateStudent"  parameterType="com.njupt.entities.Student">
                   update student set name=#{name}, age=#{age} where id =  #{id}
            </update>
              <!-- resultType 可以省略 -->
            <delete id="deleteStudent">
                   delete from student where id=#{id}
            </delete>
    </mapper>
  3. 使用方法
  4.     public void getStudentById() throws IOException{
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources. getResourceAsStream( resource);
            //1.获取sqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream);
            //2.获取SqlSession对象那个
            SqlSession session = sqlSessionFactory.openSession();
            //会为接口自动创建一个代理对象,代理对象执行对应的方法
            StudentMapper studentMapper = session.getMapper(StudentMapper. class);
            Student student = studentMapper.getStudentById(1);
            System. out.println( student);
            int tmp = studentMapper.addStudent( new Student( "aaa",18));
            session.commit();
        }
  5. 增删改的注意事项
    1. sqlSessionFactory .openSession()这种方式不会自动提交修改, sqlSessionFactory .openSession(true)这样会自动提交
    2. 增删改标签没有 resultType标签,但是会返回操作的数据行数。可以自动转为int,long,boolean类型
  6. 添加并获取自增主键
  7.      useGeneratedKeys表示使用自增主键,keyProperty表示将使用jDBC操作获取的id赋值给参数的哪个属性
       < insert id= "addStudent" parameterType= "com.njupt.entities.Student" useGeneratedKeys= "true" keyProperty= "id" >
          insert into student(name,age) values(#{name},#{age})
       </ insert >
       String resource = "mybatis-config.xml";
       InputStream inputStream = Resources. getResourceAsStream( resource);
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream);
       SqlSession session = sqlSessionFactory.openSession();
       StudentMapper studentMapper = session.getMapper(StudentMapper. class);
       Student student = new Student( "bbb",18); //此时student的id是没有值的
        int tmp = studentMapper.addStudent( student);
       System. out.println( student.getId()); //输出3
       session.commit();
       System. out.println( student.getId()); //输出3
3.Mybatis参数处理
  1. 只有一个参数时,Mybatis不做处理,随便取,都可以取出来
    1. public Student getStudentById(Integer id);
    2. < select id= "getStudentById" resultType= "com.njupt.entities.Student" >
    3.     select * from student where id=#{id}//这里的#{}可以随便写,#{a},#{b}
    4. </ select >
  2. 当有多个参数时,Mybati会将多个参数封装成map
    1. key为param1,param2.......paramN; value为参数值
    2. 或者采用#{0},#{1}这种根据索引取值
    3. 使用@param注解指定key
      1. public Student getStudentByIdAndName( @Param( "id") int id, @Param( "name")String name);
      2. < select id= "getStudentByIdAndName" resultType= "com.njupt.entities.Student" >
      3.     select * from student where id=#{id} and name=#{name}
      4. </ select >
    4. 直接使用POJO对象
      1. public int addStudent(Student student);
    5. 如果多个参数不是实体类,但是又经常使用,那么就自定义一个参数实体类,专门用来传参
    6. 将多个参数封装成map,直接传入自定义的map
  3. 当传入的参数是Collection(List,Set)的对象时,也特殊处理
    1. Collection=====>#{collection}
    2. List=====>#{list[0]},List的默认键为list
    3. Set======>#{set}
      1. public Student getStudentByIds(List<Integer> ids);
      2. < select id= "getStudentByIds " resultType= "com.njupt.entities.Student" >
      3.     select * from student where id=#{list[0]}
      4. </ select >
  4. 示例,考虑以下场景如何取值
    1. public Student getStudentByIdAndName( @Param( "id") int id,String name);
      1. id==>#{id/param1}   name==>#{param2}
    2. public Student getStudentByIdAndName( @Param( "id") int id,Student  student);
      1. id==>#{id/param1}, name==>#{param2.name}
  5. #{}与${}都可以取出参数的值,他们有什么区别
    1. #{}:是以预编译的形式,将参数设置到sql语句中,PreparedStatement; 可以防止sql注入
    2. ${}:取出的值直接拼接在sql语句中
    3. 什么情况下使用#{}与${}
      1. 只要支持PreparedStatement的,都采用#{}
      2. 不支持PreparedStatement都采用${},例如,表名,排序等
        1. select * from 2016_table/2017_table/2018_table   -->select *from table ${year}_table
        2. select * from table order by ${f_name} ${order}
  6. #{}:还可以规定参数的一些规则
    1. javaType, jdbcType, mode(存储过程),numericScale(保留小数位数),resultMap, typeHandler,jdbcTypeName,expression
    2. javaType通常在某些特定条件下需要被设置
      1. 假设添加email字段为null,java类型:null----映射---->jdbc类型:OTHER。而oracle不支持OTHER类型就会报错
      2. 解决方案一:修改全局配置
        1. <setting name="jdbcTypeForNull" value="NULL"/>
      3. 解决方案二:
      1. #{email,jdbcType=NULL}
4.查询语句的细节
  1. 查询语句返回一个List那么ResultType应该放的是List中元素的类型
    1. public List<Student> getStudentsGreaterThanAge( @Param( "age") int age);  
    2. < select id= "getStudentsGreaterThanAge" resultType= "com.njupt.entities.Student" >
    3.     select * from student where age>=#{age}
    4. </ select >
  2. 返回map
    1. 返回一个map,键为数据库的列名,值为数据库的值
      1. public Map<String,Object> getMapById( @Param( "age") int id);
      2. < select id= "getMapById" resultType= "map" >
      3.      select * from student where id=#{id}
      4. </ select >
    2. 返回一个map,键为指定的键,值为POJO对象
      1. @MapKey( "id")
      2. public Map<Integer, Student> getStudentsByAge( @Param( "age") int age);
      3. < select id= "getStudentsByAge" resultType= "com.njupt.entities.Student" >  
      4.     select * from student where age>=#{age}
      5. </ select >
    3. 如果数据库列名与javaBean属性字段不匹配,返回结果无法封装成javaBean,该怎么办
      1. 给列名起别名
      2. 满足驼峰命名法,我们在全局配置文件中开启驼峰命名法
      3. 使用 resultMap自定义映射
        1. <!-- type表示封装的javaBean类型,id为这个映射规则返回的Map类型的别名 -->
        2. < resultMap type= "com.njupt.entities.Student" id= "stu" >
        3.      <!-- 元素id表示主键映射, coulumn 表示数据库的哪一列,property表示映射为javaBean的哪个属性 -->
        4.      < id column= "id" property= "id" />
        5.      <!-- 元素result表示普通列的映射, coulumn 表示数据库的哪一列,property表示映射为javaBean的哪个属性 -->
        6.      < result column= "name" property= "name" />
        7. </ resultMap >
        8. < select id= "getStudentsByAge" resultMap= "stu" >
        9.     select * from student where age>=#{age}
        10. </ select >
  3. resultMap的高级用法
    1. 一对一,如果javaBean对象内的属性也有一个对象该怎么做呢,例如学生信息里有学校
      1. 联合查询
        1. 级联属性
          1. < resultMap type= "com.njupt.entities.Student" id= "stuPlus" >
          2.      < id column= "id" property= "id" />
          3.      < result column= "name" property= "name" />
          4.      < result column= "scId" property= "school.id" />
          5.      < result column= "scName" property= "school.name" />
          6. </ resultMap >
          7. < select id= "getStudentById" resultMap= "stuPlus" >
          8.     select st.id id,st.name name, st.sc_id schoolId, sc.id scId, sc.name scName
          9.     from student st
          10.     inner join school sc
          11.     on st.sc_id=sc.id
          12.     where id=#{id}
          13. </ select >
        2. 利用 association标签实现属性对象的封装
          1. < resultMap type= "com.njupt.entities.Student" id= "stuPlus" >
          2.      < id column= "id" property= "id" />
          3.      < result column= "name" property= "name" />
          4.      < association property= "school" javaType= "com.njupt.entities.School" >
          5.           < id column= "scId" property= "id" />
          6.           < result column= "scName" property= "name" />
          7.      </ association >
          8. </ resultMap >
      2. 分步查询 association
        1. 学生内有一个属性时学校,我们可以先查出学生信息,然后根据查出的学生信息的scId,再去查学校信息
    2. 一对多,如果一个学校含有很多学生,该怎么查呢 collection
      1. 联合查询
        1. < resultMap type= "com.njupt.entities.School" id= "sch" >
        2.      < id column= "id" property= "id" />
        3.      < result column= "name" property= "name" />
        4.      < collection property= "stuList" ofType= "com.njupt.entities.Student" >
        5.              < id column= "stId" property= "id" />
        6.              < result column= "stName" property= "name" />
        7.      </ collection >
        8. </ resultMap >
        9. < select id= "getAllStudentsInSchool" resultMap= "sch" >
        10.      select sc.id id,sc.name name, st.id stId, st.name stName
        11.      from school sc
        12.      inner join  student st
        13.      on sc.id=st.sc_id
        14.      where id=#{id}
        15. </ select >
      2. 分步查询
        1. < resultMap type= "com.njupt.entities.School" id= "sch" >
        2.      < id column= "id" property= "id" />
        3.      < result column= "name" property= "name" />
        4.      < collection property= "stuList" select= "com.njupt.mapper.StudentMapper.getStudentsByScId" column= "id" >
        5.      </ collection >
        6. </ resultMap >
        7. < select id= "getAllStudentsInSchool" resultMap= "sch" >
        8.      select id, name
        9.      from school
        10.      where id=#{id}
        11. </select>
    3. 扩展
      1. 在上面的示例中,第二步查询只传递了一个参数,如果有多个参数怎么办 column= "{id=id,name=name}"
        1. < collection property= "stuList" select= "com.njupt.mapper.StudentMapper.getStudentsByScId" column= "{id=id,name=name}" >
  4. 延迟加载,考虑到 association每次都会发送两条sql,当我们调用某个字段时,才去发送对应的sql,我们需要开启延迟加载
    1. 全局配置
      1. < setting name= "lazyLoadingEnabled" value= "true" />开启延迟加载
      2. < setting name= "aggressivelazyLoadingEnabled" value= "false" />关闭非延迟加载
    2. 分步查询的标签有个字段 fetchType也可设置延迟加载,且其优先级高于全局配置
      1. < collection property= "stuList" select= "com.njupt.mapper.StudentMapper.getStudentsByScId" column= "id" fetchType= "lazy" >
5.动态sql
  1. if标签
    1. 要求根据传过来的参数,字段非空,来设置sql语句
      1. < select id= "getStudentByIf" resultType= "com.njupt.entities.Student" >
      2.     select * from student where
      3.      < if test= "id!=null" >id=#{id} </ if >
      4.      < if test= "name!=null and name!='' " >and name=#{name} </ if >
      5. </ select >
      6. OGNL虽然支持&& 等逻辑判断,但是由于在xml中&属于特殊字符,需要使用html的实体字符来替代
  2. where标签,用于查询时去除头部多余的and
    1. 对于上面的sql拼装,我们发现如果id为空,那么sql语句就变为了。select * from student where and name=#{name}这就错了
    2. where标签可以去除头部的and或者or等
      1. < select id= "getStudentByIf" resultType= "com.njupt.entities.Student" >
      2.     select * from student
      3.      < where >
      4.          < if test= "id!=null" >id=#{id} </ if >
      5.          < if test= "name!=null and name!='' " >and name=#{name} </ if >
      6.      </ where >
      7. </ select >
  3. trim标签
    1. prefix:给trim标签体最终返回的结果,加一个前缀
    2. prefixOverrides:给trim标签体最终返回的结果,删除指定前缀
    3. suffix:给trim标签体最终返回的结果,加一个后缀
    4. suffixOverrides:给trim标签体最终返回的结果,删除指定后缀
    5. < select id= "getStudentByIf" resultType= "com.njupt.entities.Student" >
    6.         select * from student        
    7.         < trim prefix= "where" prefixOverrides= "" suffix= "" suffixOverrides= "and" >
    8.             < if test= "id!=null" >id=#{id} and </ if >
    9.             < if test= "name!=null and name!='' " > name=#{name} </ if >
    10.         </ trim >
    11.     </ select >
  4. choose标签,分支选择,相当于带了break的switch-case语句
    1. 进行一个查询,带了id字段就用id查询,带了name字段就用name查询
    2. < select id= "getStudentByIf" resultType= "com.njupt.entities.Student" >
    3.     select * from student        
    4.      < where >
    5.          < choose >
    6.              < when test= "id!=null" > id=#{id} </ when >
    7.              < when test= "name!=null" >name=#{name} </ when >
    8.              < otherwise >1=1 </ otherwise >
    9.          </ choose >
    10.      </ where >
    11. </ select >
  5. set标签,用于去除更新操作时,多余的逗号","
    1. < update id= "updateStudent" >
    2.     update student
    3.      < set >
    4.          < if test= "name!=null" >name=#{name}, </ if >
    5.          < if test= "age!=null" >age=#{age} </ if >
    6.      </ set >
    7.      < where >
    8.         id=#{id}
    9.      </ where >
    10. </ update >
  6. foreach标签,用于批量操作
    1. 批量删除,方法1,
      1.   public int deleteMoreStu(String ids);   
      2. < delete id= "deleteMoreStu" >
      3.     delete from student where id in (${ ids})
      4. </ delete >
      5. studentMapper.deleteMoreStu( "1,2,3,4,5");
    2. 利用 foreach批量处理集合,
      1. collection:集合名
      2. item:集合内的每个元素的临时名称
      3. open:在循环结束后得到的结果前面,添加的字符串
      4. close:在循环结束后得到的结果后面,添加的字符串
      5. index:如果Collection为List,则index为下标。如果为Map,则index为键
      6. separator:分隔符
      7. public int deleteMoreStu( @Param( "ids")List<Integer> ids);
      8. < delete id= "deleteMoreStu" >
      9.     delete from student where id in 
      10.      < foreach collection= "ids" item= "id" open= "(" close= ")" separator= "," >//如果没有用@Param修饰,collection=“list”
      11.         #{id}
      12.      </ foreach >
      13. </ delete >
    3. 批量操作
      1. delete
        1. delete from student where id in ()
        2. delete from student where id=1 or id=2
      2. select
        1. select * from student where id in ()
        2. select * from student where id=1 or  id=2
      3. update:
        1. 批量修改
      4. insert
        1. insert into student(name,age) values ("www",24),("yh",25),("xiaowang",18)
        2. public int insertMoreStudents( @Param( "stuList")List<Student> stuList);
        3. < insert id= "insertMoreStudents" parameterType= "com.njupt.entities.Student" >
        4.     insert into student(name,age) values
        5.      < foreach collection= "stuList" item= "stu" separator= "," >
        6.         (#{stu.name}, #{stu.age})
        7.      </ foreach >
        8. </ insert >
  7. sql标签用于抽取可重用sql语句片段,支持判断语句
    1. < sql id= "insertCols" >name,age </ sql >
    2. < insert id= "insertMoreStudents" parameterType= "com.njupt.entities.Student" >
    3.     insert into student( < include refid= "insertCols" ></ include >) values
    4.      < foreach collection= "stuList" item= "stu" separator= "," >
    5.         (#{stu.name}, #{stu.age})
    6.      </ foreach >
    7. </ insert >
  8. 内置参数
    1. _parameter:代表整个参数
      1. 单个参数:_parameter就是这个参数
      2. 多个参数:参数会被封装为一个map,_parameter就是这个map
    2. _databaseId:如果配置了databaseIdProvider标签
      1. _databaseId:就代表当前数据库的别名
6.缓存
  1. 一级缓存(本地缓存):其实就是sqlSession对象的一个Map. sqlSession级别的缓存,一级缓存是一直开启的,无法关闭
    1. 与数据库 同一次会话期间查询到的数据会放到本地缓存中,以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库。
    2. 一级缓存失效情况(即执行同样的sql会访问数据库)
      1. sqlSession不同
      2. sqlSession相同,查询条件不同
      3. sqlSession相同,查询条件相同,但是两次查询期间,执行了增删改操作
      4. sqlSession相同,手动清除了缓存,session.clearCache()
  2. 二级缓存(全局缓存):基于namespace的缓存,即一个Mapper.XML文件,对应一个二级缓存
    1. 工作机制
      1. 一个会话,查询一条数据,这个数据会被放在当前sqlSession的一级缓存中
      2. 如果 会话关闭或者提交,当前缓存会被保存到二级缓存中,新的会话查询信息,可以参照二级缓存。
      3. 不同的namespace查出的数据会放在自己对应的缓存(map)中
    2. 使用
      1. 全局配置文件中开启全局二级缓存配置
        1. < setting name= "cacheEnabled" value= "true" />开启二级缓存
      2. 对要开启二级缓存的Mapper.XML中,启动二级缓存
        1. eviction:缓存回收策略
          1. LRU-最近最少使用,移除最长时间不被使用的对象,默认
          2. FIFO-先进先出,按对象进入缓存的顺序移除他们
          3. SOFT-软引用,移除基于垃圾回收器状态和引用规则的对象
          4. WEAK-弱引用,更积极地移除基于垃圾回收器状态和引用规则的对象
        2. flushInterval:缓存刷新间隔,缓存多长时间清空一次,默认不清空,单位毫秒
        3. readOnly:缓存是否只读,默认false
          1. true:只读,mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改原数据,因此,maybatis直接返回数据的引用,效率较高。
          2. false:非只读。获取的数据可能会被用户修改,那么mybatis就不会将原数据的引用交给用户,而是利用序列化技术,返回给用户一个副本。安全,速度慢
        4. size:默认缓存内存大小
        5. type:自定义缓存的全类名,实现Cache接口
        6. < mapper namespace= "com.njupt.mapper.StudentMapper" > <!-- 接口全类名 -->
        7.     < cache eviction= "FIFO" flushInterval= "1000" readOnly= "false" ></ cache >
      3. POJO对象实现序列化接口
        1. 由于二级缓存使用序列化技术,因此POJO对象需要实现Serializable接口
  3. 和缓存有关的设置
    1. < setting name= "cacheEnabled" value= "false" />关闭二级缓存,一级缓存一直开着
    2.   < select id= "" useCache= "true" ></ select >,UseCahe标签默认为true,设置是否使用二级缓存,
    3. < delete id= "deleteMoreStu" flushCache= "true" > flushCache默认为true,即每次增删改都会清空一二级缓存
    4. sqlSession.clearCache()只会清空一级缓存
    5. < setting name= "localCacheScope" value= "false" />一级缓存的作用域
      1. SESSION:缓存作用域为Session
      2. STATEMENT:缓存作用域为Statement,相当于禁用了缓存
  4. 缓存的使用顺序,二级缓存-->一级缓存-->数据库
  5. 缓存的实现原理
    1. 我们知道缓存就是一个Map,那么其接口为
      1.  
    2. Cache接口的实现类
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值