2021年3月8日星期一

Java学习-Mybatis

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 | falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true | falseFalse
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提供的日志工厂

image-20210305102702889

  • 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 元素也会将它们去除。

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。

<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 是值。

image-20210307152224232

<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

跨境电商:https://www.ikjzd.com/

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

没有评论:

发表评论