- 框架是 可被应用开发者定制的应用骨架html
- 框架是一种规则,保证开发者遵循相同的方式开发程序java
- 框架提倡"不要重复造轮子",对基础功能进行封装mysql
- 极大提升了开发效率算法
- 统一的编码规则,利于团队管理sql
- 灵活配置的应用,拥有更好的维护性数据库
- MyBatis是优秀的持久层框架:apache
经过DAO类结合Mybatis框架让咱们快速完成对数据的增删改查,缓存
持久就是将内存中的数据保存到数据库中,防止重启后数据丢失.安全
- MyBatis使用XML将SQL与程序解耦,便于维护session
- MyBatis学习简单,执行高效.是JDBC的延申
官网:https://mybatis.org/mybatis-3/zh/index.html
1 2
3 pojo 4
5 6
MyBatis是经过SqlSession对象对数据进行操做的,SqlSession对象由SessionFactory的对象生成。
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&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>
SqlSessionFactory
SqlSession
添加单元测试框架,经过单元测试能够了解程序的状况
该包中新建一个测试类
在方法上写test注解
只有添加了test注解,junit才能对这个类执行
文本文件
返回reader对象
build经过reader对象解析xml,返回对应的sqlsessionfactory对象
opensession:建立一个sqlsession对象
getConnection:得到底层的数据库链接对象
如何保证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 }
测试类中使用
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 }
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 < #{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 < 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>
注意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还能够本身进行扩展字段
扩展一个java对象 对多表查询返回的结果进行保存
对goods对象进行扩展
如何让mybatis自动对其进行对应赋值呢?
测试类:
resultMap中对应数据库的字段的属性应该是column
什么是日志?
执行后,在控制台能够看到打印出来的sql语句
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日志组件
先往日志中写,经过commit提交后会一次性把全部日志写入数据表中
若是发现有数据丢失,客户端能够发起回滚功能,这时事务日志中的全部日志将会所有被删除
MyBatis写操做包含三种:
新增:
获取最新插入的主键:selectKey和useGeneratedKeys
oracle中要用序列sql实现
更新:
删除:
Map的适用场景
- 为SQL语句传入多个参数
- 查询返结果包含跨表字段
应用场景:
根据选择条件搜索
为了解决上述问题,使用where标签,自动判断and是否会产生语法错误
一级缓存,每一个对象有一个,用完释放就没有了
相同命名空间的二级缓存中,一级缓存是能够共享的
总结:
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结果不会放入缓存
应用:商品和详情对象关联查询
1)Mysql
2)Oracle
3)SQL Server 2000
4)SQL Server 2012+