Mybatis
Maven依赖:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version></dependency>
持久层
持久化就是将持久状态和瞬时状态转化的过程
数据库(JDBC),IO文件持久化
1、第一个Mybatis程序
1.1、基础配置
- 编写Mybatis的核心配置文件
<?
- 编写Mybatis工具类
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.
1.2、编写代码
- 实体类
public class User { private int id; private String name; private String password; public User(int id, String name, String password) { this.id = id; this.name = name; this.password = password; } public User() { } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }}
- Dao接口
public interface UserDao { public List<User> getUserList();}
- 接口实现类,由原来的UserDaoImpl转变为Mapper配置文件
<?
1.3测试
注意点:org.apache.ibatis.binding.BindingException: Type interface com.darker.dao.UserDao is not known to the MapperRegistry.
<!--每一个Mapper.
- 测试代码
public class UserDaoTest { @Test public void test() { //获得session对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //方式一:getMapper执行sql UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } //关闭SqlSession sqlSession.close(); }}
2、CRUD
1、namespace
namespace中的报名要喝Da/mapper接口的包名一致
2、select
选择,查询语句:
id:对应namespace接口中的方法名
resultType:Sql语句执行的返回值
parameterType:参数类型
<select id="getUserList" resultType="com.darker.pojo.User"> select * from user</select>
3、insert
<insert id="addUser" parameterType="com.darker.pojo.User"> insert into user values (#{id}, #{name}, #{password});</insert>
4、update
<update id="updateUser" parameterType="com.darker.pojo.User"> update user set name = #{name}, password = #{password} where id = #{id};</update>
5、delete
<delete id="deleteUser" parameterType="int"> delete from user where id = #{id}</delete>
6、注意点
增删改需要sqlSession.commit();
提交事物。
7、Map
假设实体类中的字段过多,考虑使用Map。
@Testpublic void addUser2() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> hashMap = new HashMap<String, Object>(); hashMap.put("userid",5); hashMap.put("username","safasdf"); hashMap.put("userpassword","2341212"); mapper.addUser2(hashMap); sqlSession.close();}
<insert id="addUser2" parameterType="map"> insert into user values (#{userid}, #{username}, #{userpassword});</insert>
//新增用户int addUser2(HashMap<String, Object> map);
8、模糊查询
在传参是使用%%
List<User> userList = mapper.getUserLikeList("%测试%");
SQL中写
select * from user where name like "%"#{value}"%"
3、配置解析
1、核心配置文件
- mybatis-config.
configuration(配置) properties(属性) settings(设置) typeAliases(类型别名) typeHandlers(类型处理器) objectFactory(对象工厂) plugins(插件) environments(环境配置) environment(环境变量) transactionManager(事务管理器) dataSource(数据源) databaseIdProvider(数据库厂商标识) mappers(映射器)
1.1、环境配置(environments)
MyBatis 可以配置成适应多种环境,但每个 SqlSessionFactory 实例只能选择一种环境。
Mybatis默认的事物管理器是JDBC,连接池:POOLED;
1.2、属性(properties)
可以通过properties属性来实现引用配置文件【db.properties】
<properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="handhand"/></properties>
可以引入外部配置文件
可以在其中增加属性配置
如果有重复的字段,优先使用外部配置文件
1.3、类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于
- 给实体类起别名
<typeAliases> <typeAlias type="com.darker.pojo.User" alias="User"/></typeAliases>
- 扫描实体类的包,他的默认别名就为这个类名的首字母小写
<typeAliases> <package name="com.darker.pojo"></typeAliases>
@Alias("helloUser")
1.4、设置(settings)
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true | false | false |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
1.5、映射器(mappers)
注册绑定我们的mapper文件
<!--每一个Mapper.
1.6、生命周期和作用域
SqlSessionFactoryBuilder
- 一旦创建了 SqlSessionFactory,就不再需要它了。
- 局部变量
SqlSessionFactory
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- SqlSessionFactory 的最佳作用域是应用作用域
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 用完后关闭
4、解决属性名和字段名不一致的问题
实体
private int id;private String name;private String pwd;//与数据库不对应
数据库字段
idnamepassword
解决方法
- 起别名
<select id="getUserById" resultType="com.darker.pojo.User" parameterType="int"> select id,name,password as pwd from user where id = #{id}</select>
- resultMap
结果集映射
<resultMap id="UserMap" type="com.darker.pojo.User"> <!--column数据库中的字段,property实体类中的属性--> <result column="id" property="id"/> <result column="name" property="name"/> <result column="password" property="pwd"/></resultMap><select id="getUserById" resultMap="UserMap" parameterType="int"> select * from user where id = #{id}</select>
5、日志
5.1日志工厂
Mybatis提供的日志工厂
- SLF4J
- LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING
- NO_LOGGING
STDOUT_LOGGING标准日志输出
Opening JDBC ConnectionCreated connection 1073763441.Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@40005471]==> Preparing: select * from user where id = ?==> Parameters: 4(Integer)<== Columns: id, name, password<== Row: 4, q3142q测试, 23131<== Total: 1User{id=4, name='q3142q测试', pwd='23131'}Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@40005471]Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@40005471]Returned connection 1073763441 to pool.
5.2、Log4j
log4j.rootLogger=DEBUG,console,file#控制台输出相关配置log4j.appender.console = org.apache.log4j.ConsoleAppenderlog4j.appender.console.Target = System.outlog4j.appender.console.Threshold = DEBUGlog4j.appender.console.layout = org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern = [%c] -%m%n#文件输出相关的配置log4j.appender.file = org.apache.log4j.RollingFileAppenderlog4j.appender.file.File = ./log/darker.loglog4j.appender.file.MaxFileSize = 10MBlog4j.appender.file.Threshold = DEBUGlog4j.appender.file.layout = org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern = [%p][%d{yyyy-MM-dd HH:mm:ss}][%c]%m%n#日志输出级别log4j.logger.org.mybatis=DEBUGlog4j.logger.java.sql=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.ResultSet=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUG
简单使用
1.导包
import org.apache.log4j.Logger;
2.日志对象,参数为当前类的class
Logger logger = Logger.getLogger(UserDaoTest.class);
3.使用
logger.info("info:进入testLog4j");logger.debug("debug:进入testLog4j");logger.error("error:进入testLog4j");
6、分页
减少数据的处理量
使用Limit分页
select * from user limit startIndex,pageSize
使用RowBounds
SqlSession sqlSession = MybatisUtils.getSqlSession();//offset,limit.从查询的第2行开始数,往后面四行数据RowBounds rowBounds = new RowBounds(1, 4);List<User> userLise = sqlSession.selectList("com.darker.dao.UserMapper.getUserByRowBounds", null, rowBounds);for (User user : userLise) { System.out.println(user.toString());}sqlSession.close();
7.注解开发
在接口上实现
@Select("select * from user")List<User> getUserListAnn();
配置文件中绑定接口
<mapper />
方法中如果有多个参数,一定要使用
@Param("id")
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加上
- 如果只有一个基本来兴,可以忽略
8、多对一的处理
需求:查询学生对应的老师信息
- 学生实体类
private long id;private String name;//关联老师private Teacher teacher;
- 老师实体类
private long id;private String name;
按照查询嵌套处理
<select id="getStdentAllInfo" resultMap="StudentTeacher"> select s.id, s.name, s.tid from student s</select><resultMap id="StudentTeacher" type="Student"> <result property="id" column="id"/> <result property="name" column="name"/> <!-- 复杂的属性,需要单独处理 association:对象 collection:集合 --> <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/></resultMap><select id="getTeacher" resultType="Teacher"> select * from teacher where id = #{id}</select>
按照结果嵌套处理
<select id="getStdentAllInfo2" resultMap="StudentTeacher2"> select s.id sid, s.name sname, t.name tname from student s left join teacher t on s.tid = t.id;</select><resultMap id="StudentTeacher2" type="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <association property="teacher" javaType="Teacher"> <result property="name" column="tname"/> </association></resultMap>
9、一对多的处理
需求:查询老师下的学生信息
- 老师实体类
private long id;private String name;private List<Student> students;
- 学生实体类
private long id;private String name;private int tid;
按照查询嵌套处理
<select id="getTeacherAllInfo2" resultMap="TeacherSdudent2"> select t.id tid, t.name tname from teacher t</select><resultMap id="TeacherSdudent2" type="Teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/> <collection property="students" column="tid" javaType="ArrayList" ofType="Student" select="getStudent"/></resultMap><select id="getStudent" resultType="Student"> select * from student where tid = #{tid}</select>
按照结果嵌套处理
<!--案结果嵌套查询--> <select id="getTeacherAllInfo" resultMap="TeacherSdudent"> select t.id tid, t.name tname, s.id sid, s.name sname from student s, teacher t where s.tid = t.id </select> <resultMap id="TeacherSdudent" type="Teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/><!-- javaType:指定属性的类型 集合中的泛型信息,用ofType获取--> <collection property="students" ofType="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap>
小结
1.关联 association【多对一】
2.集合 collection 【一对多】
3.javaType 和 ofType
javaType 用来指定实体类中的属性类型
ofType 用来指定映射到List或者集合中的POJO类型,泛型中的约束类型
10、动态SQL
在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
if
if标签中tes属性必输
<select id="queryBlogIF" parameterType="map" resultType="Blog"> select * from blog where 1=1 <if test="title != null"> and title like #{title} </if> <if test="author != null"> and author like #{author} </if></select>
choose (when, otherwise)
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="queryBlogChoose" parameterType="map" resultType="Blog"> select * from blog <where> <choose> <when test="title != null"> and title like #{title} </when> <when test="author != null"> and author like #{author} </when> <otherwise> 1=1 </otherwise> </choose> </where></select>
trim (where, set)
where 元素只会在子元素返回任何内容的情况下才插入 "WHERE" 子句。而且,若子句的开头为 "AND" 或 "OR",where 元素也会将它们去除。
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。
<update id="updateBlog" parameterType="map"> update blog <set> <if test="title !=null"> title = #{title}, </if> <if test="author !=null"> author = #{author}, </if> </set> where id = #{id}</update>
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
<select id="queryBlogForeach" parameterType="map" resultType="Blog"> select * from blog <where> <foreach item="id" collection="ids" open="and (" separator="or" close=")"> id = #{id} </foreach> </where></select>
sql拼接结果:select * from blog WHERE ( id = ? or id = ? )
SQL片段
将公共的部分抽取出来,方便复用
使用sql标签抽取公共部分
在要用的时候是用include标签引用
<sql id="if-title-authoe"> <if test="title != null"> and title like #{title} </if> <if test="author != null"> and author like #{author} </if></sql><select id="queryBlogIF" parameterType="map" resultType="Blog"> select * from blog where 1=1 <include refid="if-title-authoe"/></select>
11、缓存
Mybatis缓存
- mybatis默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启,(Sqlsession级别的缓存,也成为本地缓存)
- 二级缓存需要手动开启,他是namespace级别的环境
- Mybatis还定义了缓存接口Cache,可以通过实现Cache接口来定义二级缓存
一级缓存
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
- 手动清除缓存
sqlSession.clearCache();
二级缓存
要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行
<cache/>
这些属性可以通过 cache 元素的属性来修改。比如:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认的清除策略是 LRU。
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
提示 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,(也就是一级缓存SqlSession .close()之后)但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。
原理
用户查询的时候,首先查看二级缓存中有没有,
如果没有则去查看一级缓存有没有,
没有就会去查询数据库。
自定义缓存ehcache
ehcache是一个分布式缓存
依赖:
<dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</version></dependency>
原文转载:http://www.shaoqun.com/a/610610.html
terapeak:https://www.ikjzd.com/w/556
捷汇:https://www.ikjzd.com/w/419
MybatisMaven依赖:<!--https://mvnrepository.com/artifact/org.mybatis/mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>
邮乐网购:https://www.ikjzd.com/w/1776
bsci:https://www.ikjzd.com/w/2339
华翰物流:https://www.ikjzd.com/w/1799
亚马逊后台如何上传Listing视频,Listing视频有哪些要求:https://www.ikjzd.com/home/7171
好消息!跨境进口新政:年度交易限额增至2.6万,新增63个税目商品!:https://www.ikjzd.com/home/11397
Wish"误导性"产品新政策,卖家知多少?:https://www.ikjzd.com/home/101963
没有评论:
发表评论