Mybatis入门

软件开发中的框架

- 框架是 可被应用开发者定制的应用骨架html

- 框架是一种规则,保证开发者遵循相同的方式开发程序java

- 框架提倡"不要重复造轮子",对基础功能进行封装mysql

框架的优势

- 极大提升了开发效率算法

- 统一的编码规则,利于团队管理sql

- 灵活配置的应用,拥有更好的维护性数据库

SSM开发框架

MyBatis入门

1 什么是MyBatis

- MyBatis是优秀的持久层框架:apache

  经过DAO类结合Mybatis框架让咱们快速完成对数据的增删改查,缓存

  持久就是将内存中的数据保存到数据库中,防止重启后数据丢失.安全

- MyBatis使用XML将SQL与程序解耦,便于维护session

- MyBatis学习简单,执行高效.是JDBC的延申

官网:https://mybatis.org/mybatis-3/zh/index.html

2 MyBatis开发流程

1 2

3 pojo 4

5 6

MyBatis是经过SqlSession对象对数据进行操做的,SqlSession对象由SessionFactory的对象生成。

 3 MyBatis环境配置

 finish

中央仓库在国外有时下载比较慢,为了解决这个问题,能够在pom.xml增长一个镜像仓库配置

 

 jdbc驱动(这里是mysql)

 IDEA内置的数据库客户端

 

有时可能出现下载不成功的状况

解决方法:

1.在Mysql官网找到对应版本的jar包: https://dev.mysql.com/downloads/connector/j/

 官网下载太慢时,能够经过MvnJar(https://www.mvnjar.com/)搜索对应的jar包来下载

2.将下载好的jar包将jar包放在IDEA的配置目录或Maven仓库中(只要能找到就行)

在IDEA的Mysql驱动文件列表中添加下载好的jar包

 

一切就绪后,点击测试链接,若是显示success表示链接成功,再点击ok就配置好了

建立一个全新的数据库并导入初始化表 (用数据源的方式)

在文件夹上点击鼠标右键

执行成功后

 

还能够修改表结构

 

 resource目录下要新建立一个xml文件

 

xml声明

dtd声明

注:

 &的转义: &

能够有多个数据源的环境配置

默认用哪一个用default设置,值为数据源对应的id的值

environment只能够配置一个数据库,每一个配置好的environment能够当作一个数据源,而environments标签用于数据源的配置,能够配置多个数据源。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration
 3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <settings>
 7         <!-- goods_id ==> goodsId 驼峰命名转换 -->
 8         <setting name="mapUnderscoreToCamelCase" value="true"/>
 9     </settings>
10 
11     <!--设置默认指向的数据库-->
12     <environments default="dev">
13         <!--配置环境,不一样的环境不一样的id名字-->
14         <environment id="dev">
15             <!-- 采用JDBC方式对数据库事务进行commit/rollback -->
16             <transactionManager type="JDBC"></transactionManager>
17             <!--采用链接池方式管理数据库链接-->
18             <dataSource type="POOLED">
19                 <property name="driver" value="com.mysql.jdbc.Driver"/>
20                 <property name="url" value="jdbc:mysql://localhost:3306/babytun?useUnicode=true&amp;characterEncoding=UTF-8"/>
21                 <property name="username" value="root"/>
22                 <property name="password" value="root"/>
23             </dataSource>
24         </environment>
25     </environments>
26     <mappers>
27         <!--<mapper class="com.imooc.mybatis.dao.GoodsDAO"/>-->
28         <package name="com.imooc.mybatis.dao"/>
29     </mappers>
30 </configuration>
View Code

4 SqlSessionFactory

SqlSessionFactory

SqlSession

添加单元测试框架,经过单元测试能够了解程序的状况

 该包中新建一个测试类

在方法上写test注解

只有添加了test注解,junit才能对这个类执行

 文本文件

返回reader对象

build经过reader对象解析xml,返回对应的sqlsessionfactory对象

opensession:建立一个sqlsession对象

getConnection:得到底层的数据库链接对象

5 初始化工具类MyBatisUtils

 如何保证SqlSessionFactory在应用中全局惟一

 1 package com.imooc.mybatis.utils;
 2 
 3 import org.apache.ibatis.io.Resources;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 7 
 8 import java.io.IOException;
 9 import java.io.Reader;
10 
11 /**
12  * MyBatisUtils工具类,建立全局惟一的SqlSessionFactory对象
13  */
14 public class MyBatisUtils {
15     //利用static(静态)属于类不属于对象,且全局惟一
16     private static SqlSessionFactory sqlSessionFactory = null;
17     //利用静态块在初始化类时实例化sqlSessionFactory
18     static {
19         Reader reader = null;
20         try {
21             reader = Resources.getResourceAsReader("mybatis-config.xml");
22             sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
23         } catch (IOException e) {
24             e.printStackTrace();
25             //初始化错误时,经过抛出异常ExceptionInInitializerError通知调用者
26             throw new ExceptionInInitializerError(e);
27         }
28     }
29 
30     /**
31      * openSession 建立一个新的SqlSession对象
32      * @return SqlSession对象
33      */
34     public static SqlSession openSession(){
35         //默认SqlSession对自动提交事务数据(commit)
36         //设置false表明关闭自动提交,改成手动提交事务数据
37         return sqlSessionFactory.openSession(false);
38     }
39 
40     /**
41      * 释放一个有效的SqlSession对象
42      * @param session 准备释放SqlSession对象
43      */
44     public static void closeSession(SqlSession session){
45         if(session != null){
46             session.close();
47         }
48     }
49 }
View Code

测试类中使用

6 MyBatis数据查询步骤

1→2

3→4

5→6

1.建立实体类

增长一些列的自由属性,与goods表一一对应,

写好字段信息后,生成get,set方法

 1 package com.imooc.mybatis.entity;
 2 
 3 import java.util.List;
 4 
 5 public class Goods {
 6     private Integer goodsId;//商品编号
 7     private String title;//标题
 8     private String subTitle;//子标题
 9     private Float originalCost;//原始价格
10     private Float currentPrice;//当前价格
11     private Float discount;//折扣率
12     private Integer isFreeDelivery;//是否包邮 ,1-包邮 0-不包邮
13     private Integer categoryId;//分类编号
14     private List<GoodsDetail> goodsDetails;
15 
16     public Integer getGoodsId() {
17         return goodsId;
18     }
19 
20     public void setGoodsId(Integer goodsId) {
21         this.goodsId = goodsId;
22     }
23 
24     public String getTitle() {
25         return title;
26     }
27 
28     public void setTitle(String title) {
29         this.title = title;
30     }
31 
32     public String getSubTitle() {
33         return subTitle;
34     }
35 
36     public void setSubTitle(String subTitle) {
37         this.subTitle = subTitle;
38     }
39 
40     public Float getOriginalCost() {
41         return originalCost;
42     }
43 
44     public void setOriginalCost(Float originalCost) {
45         this.originalCost = originalCost;
46     }
47 
48     public Float getCurrentPrice() {
49         return currentPrice;
50     }
51 
52     public void setCurrentPrice(Float currentPrice) {
53         this.currentPrice = currentPrice;
54     }
55 
56     public Float getDiscount() {
57         return discount;
58     }
59 
60     public void setDiscount(Float discount) {
61         this.discount = discount;
62     }
63 
64     public Integer getIsFreeDelivery() {
65         return isFreeDelivery;
66     }
67 
68     public void setIsFreeDelivery(Integer isFreeDelivery) {
69         this.isFreeDelivery = isFreeDelivery;
70     }
71 
72     public Integer getCategoryId() {
73         return categoryId;
74     }
75 
76     public void setCategoryId(Integer categoryId) {
77         this.categoryId = categoryId;
78     }
79 
80     public List<GoodsDetail> getGoodsDetails() {
81         return goodsDetails;
82     }
83 
84     public void setGoodsDetails(List<GoodsDetail> goodsDetails) {
85         this.goodsDetails = goodsDetails;
86     }
87 }
View Code

2.建立mapper  xml

说明实体类和哪一个表对应

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <!DOCTYPE mapper
  3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5 <mapper namespace="goods">
  6     <!--开启了二级缓存
  7         eviction是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清除
  8             1.LRU – 最近最少使用的:移除最长时间不被使用的对象。
  9             O1 O2 O3 O4 .. O512
 10             14 99 83 1     893
 11             2.FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
 12             3.SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
 13             4.WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
 14 
 15         flushInterval 表明间隔多长时间自动清空缓存,单位毫秒,600000毫秒 = 10分钟
 16         size 缓存存储上限,用于保存对象或集合(1个集合算1个对象)的数量上限
 17         readOnly 设置为true ,表明返回只读缓存,每次从缓存取出的是缓存对象自己.这种执行效率较高
 18                  设置为false , 表明每次取出的是缓存对象的"副本",每一次取出的对象都是不一样的,这种安全性较高
 19     -->
 20     <cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>
 21     <!-- useCache="false"表明不使用缓存 -->
 22     <select id="selectAll" resultType="com.imooc.mybatis.entity.Goods" useCache="false">
 23         select * from t_goods order by goods_id desc limit 10
 24     </select>
 25     <!-- 单参数传递,使用parameterType指定参数的数据类型便可,SQL中#{value}提取参数-->
 26     <select id="selectById" parameterType="Integer" resultType="com.imooc.mybatis.entity.Goods">
 27         select * from t_goods where goods_id = #{value}
 28     </select>
 29 
 30     <!-- 多参数传递时,使用parameterType指定Map接口,SQL中#{key}提取参数 -->
 31     <select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
 32         select * from t_goods
 33         where
 34           current_price between  #{min} and #{max}
 35         order by current_price
 36         limit 0,#{limt}
 37     </select>
 38 
 39     <!-- 利用LinkedHashMap保存多表关联结果
 40         MyBatis会将每一条记录包装为LinkedHashMap对象
 41         key是字段名  value是字段对应的值 , 字段类型根据表结构进行自动判断
 42         优势: 易于扩展,易于使用
 43         缺点: 太过灵活,没法进行编译时检查
 44      -->
 45     <select id="selectGoodsMap" resultType="java.util.LinkedHashMap" flushCache="true">
 46         select g.* , c.category_name,'1' as test from t_goods g , t_category c
 47         where g.category_id = c.category_id
 48     </select>
 49 
 50     <!--结果映射-->
 51     <resultMap id="rmGoods" type="com.imooc.mybatis.dto.GoodsDTO">
 52         <!--设置主键字段与属性映射-->
 53         <id property="goods.goodsId" column="goods_id"></id>
 54         <!--设置非主键字段与属性映射-->
 55         <result property="goods.title" column="title"></result>
 56         <result property="goods.originalCost" column="original_cost"></result>
 57         <result property="goods.currentPrice" column="current_price"></result>
 58         <result property="goods.discount" column="discount"></result>
 59         <result property="goods.isFreeDelivery" column="is_free_delivery"></result>
 60         <result property="goods.categoryId" column="category_id"></result>
 61         <result property="category.categoryId" column="category_id"></result>
 62         <result property="category.categoryName" column="category_name"></result>
 63         <result property="category.parentId" column="parent_id"></result>
 64         <result property="category.categoryLevel" column="category_level"></result>
 65         <result property="category.categoryOrder" column="category_order"></result>
 66 
 67 
 68         <result property="test" column="test"/>
 69     </resultMap>
 70     <select id="selectGoodsDTO" resultMap="rmGoods">
 71         select g.* , c.*,'1' as test from t_goods g , t_category c
 72         where g.category_id = c.category_id
 73     </select>
 74     <!--flushCache="true"在sql执行后强制清空缓存-->
 75     <insert id="insert" parameterType="com.imooc.mybatis.entity.Goods" flushCache="true">
 76         INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
 77         VALUES (#{title} , #{subTitle} , #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId})
 78       <!--<selectKey resultType="Integer" keyProperty="goodsId" order="AFTER">-->
 79           <!--select last_insert_id()-->
 80       <!--</selectKey>-->
 81     </insert>
 82 
 83     <update id="update" parameterType="com.imooc.mybatis.entity.Goods">
 84         UPDATE t_goods
 85         SET
 86           title = #{title} ,
 87           sub_title = #{subTitle} ,
 88           original_cost = #{originalCost} ,
 89           current_price = #{currentPrice} ,
 90           discount = #{discount} ,
 91           is_free_delivery = #{isFreeDelivery} ,
 92           category_id = #{categoryId}
 93         WHERE
 94           goods_id = #{goodsId}
 95     </update>
 96     <!--delete from t_goods where goods_id in (1920,1921)-->
 97     <delete id="delete" parameterType="Integer">
 98         delete from t_goods where goods_id = #{value}
 99     </delete>
100 
101     <select id="selectByTitle" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
102         select * from t_goods where title = #{title}
103         ${order}
104     </select>
105 
106     <select id="dynamicSQL" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
107         select * from t_goods
108         <where>
109           <if test="categoryId != null">
110               and category_id = #{categoryId}
111           </if>
112           <if test="currentPrice != null">
113               and current_price &lt; #{currentPrice}
114           </if>
115         </where>
116     </select>
117 
118     <!--
119         resultMap可用于说明一对多或者多对一的映射逻辑
120         id 是resultMap属性引用的标志
121         type 指向One的实体(Goods)
122     -->
123     <resultMap id="rmGoods1" type="com.imooc.mybatis.entity.Goods">
124         <!-- 映射goods对象的主键到goods_id字段 -->
125         <id column="goods_id" property="goodsId"></id>
126         <!--
127             collection的含义是,在
128             select * from t_goods limit 0,1 获得结果后,对全部Goods对象遍历获得goods_id字段值,
129             并代入到goodsDetail命名空间的findByGoodsId的SQL中执行查询,
130             将获得的"商品详情"集合赋值给goodsDetails List对象.
131         -->
132         <collection property="goodsDetails" select="goodsDetail.selectByGoodsId"
133                     column="goods_id"/>
134     </resultMap>
135     <select id="selectOneToMany" resultMap="rmGoods1">
136         select * from t_goods limit 0,10
137     </select>
138 
139     <select id="selectPage" resultType="com.imooc.mybatis.entity.Goods">
140         select * from t_goods where current_price &lt; 1000
141     </select>
142 
143     <!--INSERT INTO table-->
144     <!--VALUES ("a" , "a1" , "a2"),("b" , "b1" , "b2"),(....)-->
145     <insert id="batchInsert" parameterType="java.util.List">
146         INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
147         VALUES
148         <foreach collection="list" item="item" index="index" separator=",">
149             (#{item.title},#{item.subTitle}, #{item.originalCost}, #{item.currentPrice}, #{item.discount}, #{item.isFreeDelivery}, #{item.categoryId})
150         </foreach>
151     </insert>
152     <!--in (1901,1902)-->
153     <delete id="batchDelete" parameterType="java.util.List">
154         DELETE FROM t_goods WHERE goods_id in
155         <foreach collection="list" item="item" index="index" open="(" close=")" separator=",">
156             #{item}
157         </foreach>
158     </delete>
159 </mapper>
View Code

注意dtd声明与以前不一样

 

namesapce:命名空间,相似java中的包,对于不一样表或不一样功能的sql语句能够指定不一样的命名空间,

      经过不一样的命名空间就能够区分开不一样的sql语句了.不一样命名空间中的sql id能够同名

 id:sql的名字

ResultType:数据返回的对象,sql语句执行完后会自动的将获得的每一条记录包装成对应的goods对象

如何让mybatis认识这个goods.xml?

要在mybatis-config.xml中声明

 下面用测试类执行写好的sql

返回的是goods对象

对于表中有下划线的字段 在实体类中因为语法问题 只能用驼峰命名法,这样会形成丢值的问题

只需在mybatis文件中增长驼峰命名法与字段名转换的配置就可

 

SQL传参

1)查询

 

 ①根据id查一条数据

第二个参数传入的值类型要与mapper中  parameterType的类型一致!

②根据价值范围查询

mybatis只支持一个parameterType的传递,若是要传递多个,parameterType中设置的就不能是某个基础类型,而是Map

 1 <!-- 单参数传递,使用parameterType指定参数的数据类型便可,SQL中#{value}提取参数-->
 2     <select id="selectById" parameterType="Integer" resultType="com.imooc.mybatis.entity.Goods">
 3         select * from t_goods where goods_id = #{value}
 4     </select>
 5 
 6     <!-- 多参数传递时,使用parameterType指定Map接口,SQL中#{key}提取参数 -->
 7     <select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
 8         select * from t_goods
 9         where
10           current_price between  #{min} and #{max}
11         order by current_price
12         limit 0,#{limt}
13     </select>

若映射文件中,SQL语句对应的id是全局惟一的,调用时也能够不写命名空间

2)MyBatis获取多表关联查询结果

 

有一个问题:返回的map中,对应的字段顺序是混乱的

由于hashmap的机制决定,key是按照key的hash值来排序的,而哈希值是一个不稳定的数字

为了保证字段的先后顺序一致

返回值不要使用Map接口,而要使用具体的对象 

 

map还能够本身进行扩展字段

 

 

7 ResultMap结果映射

扩展一个java对象 对多表查询返回的结果进行保存

对goods对象进行扩展

如何让mybatis自动对其进行对应赋值呢?

 

 测试类:

 resultMap中对应数据库的字段的属性应该是column

8 MyBatis日志输出

什么是日志?

9 MyBatis内置日志工厂

 

step1 添加依赖

 

 

执行后,在控制台能够看到打印出来的sql语句

 

step 2 展示日志 自定义日志 

resource文件夹下新建logback.html文件

appender 输出器

class 不能随便写 意思是向控制台进行打印输出 

pattern 输出时间 + 线程名称 + 日志级别(-5:按五个字符右对齐) + 是哪一个类产生的日志({36}:最多容许36字符,超过会采用简写形式)  +  具体的日志输出内容 + 换行

root 打印的跟标签

level 日志输出级别

appender-ref的ref属性 :debug级别以上的信息都会按照pattern中定义的格式在console中输出,开发环境通常设置为debug,生产环境,通常设置为info.

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <configuration>
 3    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
 4        <encoder>
 5            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
 6        </encoder>
 7    </appender>
 8 
 9     <!--
10         日志输出级别(优先级高到低):
11         error: 错误 - 系统的故障日志
12         warn: 警告 - 存在风险或使用不当的日志
13         info: 通常性消息
14         debug: 程序内部用于调试信息
15         trace: 程序运行的跟踪信息
16      -->
17     <root level="debug">
18         <appender-ref ref="console"/>
19     </root>
20 </configuration>

logback官网:http://logback.qos.ch/     

  文档(Documentation)中能够看到各类logback的配置细节

logback中文网:http://www.logback.cn/

MyBatis配置SLFJ日志组件 

10 数据库事务

先往日志中写,经过commit提交后会一次性把全部日志写入数据表中

若是发现有数据丢失,客户端能够发起回滚功能,这时事务日志中的全部日志将会所有被删除

11 MyBatis数据写入 

MyBatis写操做包含三种:

新增:

获取最新插入的主键:selectKeyuseGeneratedKeys

 

 

oracle中要用序列sql实现

 

更新:

删除:

12 Map的妙用

Map的适用场景

 - 为SQL语句传入多个参数

 - 查询返结果包含跨表字段

13 ResultMap结果映射

14 MyBatis预防SQL注入攻击

15 MyBatis工做流程

16 动态sql

应用场景:

根据选择条件搜索

 

 

 为了解决上述问题,使用where标签,自动判断and是否会产生语法错误

17  Mybatis二级缓存

一级缓存,每一个对象有一个,用完释放就没有了

相同命名空间的二级缓存中,一级缓存是能够共享的

总结:

1.

不一样对象,同一个session,相同的sql写了两次,只执行一次

相同的对象,不一样的session,相同的sql分别写了一次,这两次都会执行

不一样对象,同一个session,两个相同的sql之间使用commit强制清空了缓存,就会执行两次

2.在实际开发中,一级缓存会被默认开启,但它的生命周期较短,缓存的开启和关闭之间只执行了少许的sql语句.

这里的缓存对象很快被释放,这也意味着缓存使用率并不高.为了解决这个问题,mybatis提供了二级缓存.

3.二级缓存须要手动开启,咱们要在对应的xml文件中进行配置(如该例子中的goods.xml)

开启了二级缓存后,在不一样的session中查询相同的数据,全局只执行了一次sql

运行结果:

 上下两个sql的哈希值也是一致的,说明他们在同一块内存中

一共执行了两次sql,第一次没有经过缓存,第二次经过缓存提取,因此命中率1/2 = 0.5

在实际开发中,缓存命中率越高代码缓存的使用效率越高.对程序优化效果越好,二级缓存存储到了命名空间这个级别上,不会由于session的开启和关闭跟着销毁.

4.二级缓存相关参数

 list返回结果不固定,缓存命中率不高,相似状况,不推荐使用二级缓存,设置useCache为false便可

通常将单一结果存入二级缓存中

内存足够的状况下.size不要过小.如1000个实体对象,size设置1000

size表示缓存存储的对象或集合的数量的上限。若是是集合,不论里面存储多少个对象,都表明一个对象

有时须要在执行一个sql以后立马清空缓存,而不是在commit后清空,只要将flushCache设置为true便可,切该条sql结果不会放入缓存

18 Mybatis多表级联查询

 

应用:商品和详情对象关联查询

19 分页插件PageHelper

 

 

PageHelper使用流程

 

不一样数据库分页的实现原理

1)Mysql

2)Oracle

3)SQL Server 2000

4)SQL Server 2012+

20 Mybatis批处理

 

21 Mybatis配置C3P0链接池

 

22 MyBatis注解开发

相关文章
相关标签/搜索