1. MyBatis

MyBatis是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

持久化:持久化就是将程序的数据在持久状态和瞬时状态转化的过程。

持久层

Dao层、Service层、Controller层

1. 第一个MyBatis程序

思路:搭建环境—> 导入Mybatis —> 编写代码 -->测试

2.1 导入Mybatis
<!--导入依赖--><dependencies><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.41</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.2</version></dependency><!--junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>

2.2 编写mybatis的核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments>
</configuration>

2.3 编写mybatis工具类

//sqlSessionFactory --> sqlSession相当于jdbc里面的preStatement
public class MybatisUtils {//提升作用域private static SqlSessionFactory sqlSessionFactory;static{try {//使用mybatis工具类获取sqlSessionFactory对象String resource="mybatis-config.xml";InputStream inputStream= Resources.getResourceAsStream(resource);sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();}
}
3 编写代码

实体类

package com.jia.pojo;
//实体类
public class User1 {private int id;private String name;private String pwd;public User1() {}public User1(int id, String name, String pwd) {this.id = id;this.name = name;this.pwd = pwd;}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 getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "User1{" +"id=" + id +", name='" + name + '\'' +", pwd='" + pwd + '\'' +'}';}
}

Dao/Mapper层

public interface UserDao {List<User1> getUserList();
}

接口实现类

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.jia.dao.UserDao"><select id="getUserList" resultType="com.jia.pojo.User1">select * from db1.user1</select>
</mapper>
测试

注意

org.apache.ibatis.binding.BindingException: Type interface com.jia.dao.UserDao is not known to the MapperRegistry.

maven资源过滤问题,由于配置文件在resources中,在maven项目中,可能导致文件导出失败。

<!--在build中配置resources,来防止我们资源导出失败的问题--><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources></build>

Junit测试

public class UserDaoTest {@Testpublic void test(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{//方式一:getMapper/*UserDao mapper = sqlSession.getMapper(UserDao.class);List<User1> userList = mapper.getUserList();*///方式二:不推荐使用List<User1> userList = sqlSession.selectList("com.jia.dao.UserDao.getUserList");for (User1 user1 : userList) {System.out.println(user1);}}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}
}

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式

2. MyBatis实现赠改查

namespace中的包名要和Mapper接口的包名一致

select:选择、查询语句:

id:就是对应的namespace中的方法名

resultType:Sql语句执行的返回值类型

parameterType:参数类型

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.jia.dao.UserMapper"><select id="getUserList" resultType="com.jia.pojo.User1">select * from db1.user1</select><select id="getUserById" resultType="com.jia.pojo.User1" parameterType="int">select * from db1.user1 where id=#{id}</select><select id="getUserById2" resultType="com.jia.pojo.User1" parameterType="map">select * from db1.user1 where id=#{id}</select><!--对象中的属性可以直接取出来--><insert id="insertUser" parameterType="com.jia.pojo.User1">insert into db1.user1(id,name,pwd) values (#{id},#{name},#{pwd})</insert><update id="updataUser" parameterType="com.jia.pojo.User1" >update db1.user1 set name=#{name},pwd=#{pwd} where id=#{id}</update><delete id="deleteUser" parameterType="com.jia.pojo.User1">delete from db1.user1 where id=#{id}</delete></mapper>

UserMapper.java

package com.jia.dao;import com.jia.pojo.User1;import java.util.List;
import java.util.Map;public interface UserMapper {//获取全部用户List<User1> getUserList();//根据id查询用户User1 getUserById(int id);User1 getUserById2(Map<String,Object> map);//插入一个用户的数据int insertUser(User1 user1);//修改用户int updataUser(User1 user1);//删除用户int deleteUser(int id);
}

UserDaoTest

package com.jia.dao;import com.jia.pojo.User1;
import com.jia.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.HashMap;
import java.util.List;public class UserDaoTest {@Testpublic void test(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{//方式一:getMapper/*UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User1> userList = mapper.getUserList();*///方式二:不推荐使用List<User1> userList = sqlSession.selectList("com.jia.dao.UserMapper.getUserList");for (User1 user1 : userList) {System.out.println(user1);}}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}@Testpublic void test2(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{//方式一:getMapperUserMapper mapper = sqlSession.getMapper(UserMapper.class);User1 user = mapper.getUserById(2);System.out.println(user);}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}//万能的map@Testpublic void test6(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{//方式一:getMapperUserMapper mapper = sqlSession.getMapper(UserMapper.class);HashMap<String, Object> map = new HashMap<>();map.put("id",1);User1 user = mapper.getUserById2(map);System.out.println(user);}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}//增删改需要提交事务@Testpublic void test3(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{//方式一:getMapperUserMapper mapper = sqlSession.getMapper(UserMapper.class);int count=mapper.insertUser(new User1(3,"王五流","323232"));System.out.println(count);//提交事务sqlSession.commit();}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}//增删改需要提交事务@Testpublic void test4(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{//方式一:getMapperUserMapper mapper = sqlSession.getMapper(UserMapper.class);int count=mapper.updataUser(new User1(3,"刘辟","3888888"));System.out.println(count);//提交事务sqlSession.commit();}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}@Testpublic void test5(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{//方式一:getMapperUserMapper mapper = sqlSession.getMapper(UserMapper.class);int count=mapper.deleteUser(2);System.out.println(count);//提交事务sqlSession.commit();}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}}

User1

//实体类
public class User1 {private int id;private String name;private String pwd;
//生成getter和setter方法

万能的Map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map

//Mapper.xml
<select id="getUserById2" resultType="com.jia.pojo.User1" parameterType="map">select * from db1.user1 where id=#{id}</select>
//Controller层
HashMap<String, Object> map = new HashMap<>();map.put("id",1);User1 user = mapper.getUserById2(map);

3. 配置解析

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息

  • configuration(配置)

    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)

        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)
  1. 环境配置(environments)

    MyBatis可以配置成适应多种环境

    尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境

    MyBatis默认事务管理器就是JDBC,连接池LPOOLED

  2. 属性(properties)

    这些属性可以在外部进行配置,并可以进行动态替换。

    你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置

    编写一个配置文件(db.properties)

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
    username=root
    password=123456
    

    在配置文件进行映入

    <!--configuration核心配置文件-->
    <configuration><!--映入外部配置文件,存在顺序关系哦--><properties resource="db.properties"/>可以使用这样的方式进行配置<property name="username" value="root" /><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册--><mappers><mapper resource="com/jia/dao/UserMapper.xml" /></mappers>
    </configuration>
    
  3. 类型别名

    类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写

    方式一:给实体类写别名的方式

    <typeAliases><typeAlias alias="Author" type="domain.blog.Author"/>
    </typeAliases>
    

    方式二:扫描实体类的包,它默认别名就为这个类的类名,首字母小写(大写也可以)

    ​ 扫描包的情况下,可以使用注解进行起别名

    //实体类
    @Alias("hello")
    public class User1 {private int id;private String name;private String pwd;
    
    <typeAliases><package name="com.jia.pojo"/>
    </typeAliases>
    

4.设置(setting)

MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

设置名 描述 有效值 默认值
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设置
mapUnderscoreToCamelCase 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 true | false False

5.其他配置

  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
    • mybatis-generator-core 代码生成
    • mybatis-plus 提高效率
    • 通用mapper

6.映射器(mappers)

MapperRegistry :注册绑定我们的Mapper文件

方式一 推荐

<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册-->
<mappers><mapper resource="com/jia/dao/UserMapper.xml" />
</mappers>

方式二:使用class文件绑定注册

<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册-->
<mappers><mapper class="com.jia.dao.UserMapper" />
</mappers>

注意:

  1. 接口必须和他的Mapper配置文件必须同名
  2. 接口和它的Mapper配置文件必须在同一个包下

方式三:使用扫描包进行注入绑定

<mappers><package name="com.jia.dao"/>
</mappers>

4. 作用域(Scope)和生命周期

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder

  • 一旦创建了SqlSessionFactory,就不再需要它了
  • 局部变量

SqlSessionFactory:

  • 可以理解为数据库连接池
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
  • SqlSessionFactory 的最佳作用域是应用作用域
  • 最简单的就是使用单例模式或者静态单例模式。

SqlSession

  • 可以理解为连接到连接池的一个请求
  • 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用

5. ResultMap结果集映射(解决属性名和字段名不一致的问题)

java实体类和数据库中字段名不一致

//实体类
public class User1 {private int id;private String name;private String pwd;

数据库中的字段名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AIJyIodn-1640586170002)(E:\Typroa笔记\MyBatis.assets\image-20211027225554748.png)]

查询的结果:

User1{id=1, name='张三', pwd='null'}
User1{id=3, name='刘辟', pwd='null'}

不一致返回的内容为null

mapper.xml运行原理:

<mapper namespace="com.jia.dao.UserMapper"><select id="getUserList" resultType="user1">select * from db1.user1//可以理解为  其中pwd和实体类中的password不对应//类型处理器 处理为:select id,name,pwd from db1.user1</select>
</mapper>

解决方法:

  1. 起别名(暴力)

    ​ select id,name,pwd as password from db1.user1 在mapoer.xml中直接起别名和实体类一致

  2. ResultMap

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dvVen7Ha-1640586170004)(E:\Typroa笔记\MyBatis.assets\image-20211027230722227.png)]

    注意:返回类型设置为resultMap

resultMap 元素是 MyBatis 中最重要最强大的元素。

ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

ResultMap 的优秀之处——你完全可以不用显式地配置它们

实体类和数据库字段名不一致的地方只需要映射一下就行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PAJlpJw8-1640586170005)(E:\Typroa笔记\MyBatis.assets\image-20211027231459480.png)]

6. 日志

6.1 日志工厂

如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手

logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设置

在Mybatis中具体使用哪一个日志实现,在设置中设定

注意顺序哦

The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
<settings><!--标准的日志工厂实现--><!--<setting name="logImpl" value="STDOUT_LOGGING"/>--><setting name="logImpl" value="LOG4J"/>
</settings>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nCWXrBVD-1640586170006)(E:\Typroa笔记\MyBatis.assets\image-20211028214910586.png)]

6.2 Log4j

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件。

我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

  1. 先导入log4j
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
   2. log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
  1. log4j的使用
<settings><!--标准的日志工厂实现--><!--<setting name="logImpl" value="STDOUT_LOGGING"/>--><setting name="logImpl" value="LOG4J"/>
</settings>
  1. 直接运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jxQsns66-1640586170008)(E:\Typroa笔记\MyBatis.assets\image-20211028221539287.png)]

简单使用:

  1. 在要使用Log4j的类中,导入包:import org.apache.log4j.Logger
  2. 日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserDaoTest.class);
  1. 日志级别
[com.jia.dao.UserDaoTest]-info...
[com.jia.dao.UserDaoTest]-debug.....
[com.jia.dao.UserDaoTest]-error....

7. 分页

思考: 为什么要分页?

  • 减少数据的处理量

使用Limint分页:

语法: SELECT * FROM user LIMIT startIndex,pageSize;
select * from user limit 3;  #[0,n]

使用Mybatis实现分页,核心SQL

  1. 接口

     //分页List<User1> getUserByLimit(Map<String,Integer> map);
    
  2. Mapper.xml

    <!--分页-->
    <select id="getUserByLimit" parameterType="map" resultType="user1">select * from db1.user1 limit #{startIndex},#{pageSize}
    </select>
    
  3. 测试

@Testpublic void getUserByLimit(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();try{UserMapper mapper = sqlSession.getMapper(UserMapper.class);HashMap<String, Integer> map = new HashMap<>();map.put("startIndex", 0);map.put("pageSize", 1);List<User1> userByLimit=mapper.getUserByLimit(map);for (User1 user1 : userByLimit) {System.out.println(user1);}}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}

7.2 RowBounds分页

  1. 接口

    //分页2 rowbounds
    List<User1> getUserByRowBounds();
    
  2. Mapper.xml

    <!--分页 RowBounds--><select id="getUserByRowBounds"  resultType="user1">select * from db1.user1</select>
    
  3. 测试

     @Testpublic void getUserByRowBounds(){//获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();//RowBounds实现RowBounds rowBounds = new RowBounds(0, 1);try{List<User1> userList = sqlSession.selectList("com.jia.dao.UserMapper.getUserByRowBounds",null,rowBounds);for (User1 user1 : userList) {System.out.println(user1);}}catch (Exception e){System.out.println(e.getMessage());}finally {//关闭SqlSessionsqlSession.close();}}
    

7.3 Mybatis分页插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qyH84Aem-1640586170010)(E:\Typroa笔记\MyBatis.assets\image-20211031110723082.png)]

8. 使用注解开发

  1. 注解在接口上实现

    public interface UserMapper {@Select("select * from db1.user1")List<User1> getUsers();
    }
    
  2. 需要在核心配置文件中绑定接口

    <!--绑定接口-->
    <mappers><mapper class="com.jia.dao.UserMapper"/>
    </mappers>
    
  3. 测试

本质 :反射机制实现

底层 :动态代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkdSTWzM-1640586170012)(E:\Typroa笔记\MyBatis.assets\image-20211031114148179.png)]

8.1 Mybatis执行流程解析

  1. Resources获取加载全局配置文件
  2. 实例化SqlSessionFactoryBuilder构造器
  3. 解析配置文件流XML ConfigBuilder
  4. Configuration所有的配置信息
  5. SqlSessionFactory实例化
  6. transactional事务管理
  7. 创建executor执行器
  8. 创建sqlSession
  9. 实现CRUD
  10. 是否执行成功 否 返回第6步
  11. 提交事务
  12. 关闭

8.3 注解增删改查

我们可以在工具类创建的时候实现自动提交事务

/既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句public static SqlSession getSqlSession(){return sqlSessionFactory.openSession(true);}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvxQuJ7L-1640586170013)(E:\Typroa笔记\MyBatis.assets\image-20211031130440660.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-edyI0hyq-1640586170014)(E:\Typroa笔记\MyBatis.assets\image-20211031130512557.png)]

测试类:

注意:我们必须要将接口注册绑定到我们的核心配置文件中

关于@Param() 注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要叫
  • 如果只有一个基本类型的化,可以忽略,但是建议加上
  • 我们在SQL中引用的就是我们这里的@Param()中设定的属性名

#{} ${}的区别

#{}和${}这两个语法是为了动态传递参数而存在的,是Mybatis实现动态SQL的基础,总体上他们的作用是一致的(为了动态传参),但是在编译过程、是否自动加单引号、安全性、使用场景等方面有很多不同,下面详细比较两者间的区别.

  1. #{} 占位符 :动态解析 -> 预编译 -> 执行
  2. ${} 拼接符 :动态解析 -> 编译 -> 执行

  1. ***#{}* 对应的变量*会*自动加上*单引号*

  2. ***${}* 对应的变量*不会*加上*单引号*


  3. ***#{}* *能*防止sql 注入

  4. ***${}* *不能*防止sql 注入

9.复杂环境的搭建

collection:一个复杂类型的集合
嵌套结果映射-集合本身可以是一个resultMap元素,或者从别处引用一个

association:一个复杂类型的关联:许多结果包装成这种类型

​ 嵌套结果映射:关联本身可以是一个resultMap元素,或者从别处引用一个

  1. 导入lombok(@Data 简化书写实体类getter等)
  2. 新建实体类Teacher,Student
  3. 建立Mapper接口
  4. 建立Mapper.xml
  5. 在核心配置文件中绑定注册我们的Mapper接口
  6. 测试查询能否能够成功

1导入lombok(@Data 简化书写实体类getter等)

父类pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!--父过程--><groupId>org.example</groupId><artifactId>com.smile.mybatis</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>mybatis-01</module><module>mybatis-02</module><module>mybatis-03</module><module>mybatis-04-anno</module><module>mybatis-05-multiple</module></modules><!--导入依赖--><dependencies><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.2</version></dependency><!--junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/log4j/log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies><!--在build中配置resources,来防止我们资源导出失败的问题--><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources></build>
</project>

子pom.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>com.smile.mybatis</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>mybatis-05-multiple</artifactId><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version></dependency></dependencies>
</project>

2新建实体类Teacher,Student

import lombok.Data;
/*** 多对一模型* lombok:相当于实体类中的getter和setter*/
@Data //getter和setter
@AllArgsConstructor   //有参构造
@NoArgsConstructor   //无参构造
public class Student {private int id;private String name;//学生需要关联一个老师private Teacher teacher;
}
@Data //getter和setter
@AllArgsConstructor   //有参构造
@NoArgsConstructor   //无参构造
public class Teacher {private int id;private String name;
}

3建立Mapper接口

import com.jia.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;public interface TeacherMapper {@Select("select * from teacher where id=#{tid}")Teacher getTeacher(@Param("tid")int id);
}

4建立Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper  namespace="com.jia.dao.TeacherMapper"></mapper>

5在核心配置文件中绑定注册我们的Mapper接口

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration><!--映入外部配置文件,存在顺序关系哦--><properties resource="db.properties"/><settings><!--标准的日志工厂实现--><!--<setting name="logImpl" value="STDOUT_LOGGING"/>--><setting name="logImpl" value="LOG4J"/></settings><!--可以给实体类写别名--><typeAliases><package name="com.jia.pojo"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--绑定接口--><mappers><mapper resource="com/jia/dao/TeacherMapper.xml" /><mapper resource="com/jia/dao/StudentMapper.xml" /></mappers>
</configuration>

6测试查询能否能够成功

import org.junit.Test;
public class MyTest {@Testpublic void test1() {SqlSession sqlSession = MybatisUtils.getSqlSession();TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);Teacher teacher = mapper.getTeacher(1);System.out.println(teacher);sqlSession.close();}static Logger logger = Logger.getLogger(MyTest.class);@Testpublic void testLog4j(){logger.info("info...");logger.debug("debug.....");logger.error("error....");}
}

7工具类

package com.jia.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;//sqlSessionFactory --> sqlSession相当于jdbc里面的preStatement
public class MybatisUtils {//提升作用域private static SqlSessionFactory sqlSessionFactory;static{try {//使用mybatis工具类获取sqlSessionFactory对象String resource="mybatis-config.xml";InputStream inputStream= Resources.getResourceAsStream(resource);sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句public static SqlSession getSqlSession(){return sqlSessionFactory.openSession(true);}
}

9.1 多对一的处理

9.1.1 按照查询嵌套处理
<mapper  namespace="com.jia.dao.StudentMapper"><!--思路:查询所有的学生信息包括另一个表中的老师select student.id,student.name,teacher.name from teacher,student where teacher.id=student.id--><select id="getStudent" resultMap="StudentTeacher">select * from student</select><resultMap id="StudentTeacher" type="Student"><result property="id" column="id"/><result property="name" column="name"/><!--另一张表中的数据 复杂的属性,我们需要单独处理  Teacher在Student中为对象,对象:association集合:collectionjavaType:对象的类型(实体类)select:嵌套查询--><association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/></resultMap><!--其实此处id=#{tid}会自动匹配,--><select id="getTeacher" resultType="Teacher">select * from teacher where id=#{id}</select>
</mapper>
import lombok.Data;
/*** 多对一模型* lombok:相当于实体类中的getter和setter*/
@Data //getter和setter
@AllArgsConstructor   //有参构造
@NoArgsConstructor   //无参构造
public class Student {private int id;private String name;//学生需要关联一个老师private Teacher teacher;
}
 @Testpublic void test3() {SqlSession sqlSession = MybatisUtils.getSqlSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);//teache参数对应studentList<Student> student = mapper.getStudent();student.forEach(item-> System.out.println(item));sqlSession.close();}
9.1.2 按照结果嵌套处理
<!--按照结果嵌套处理:--><select id="getStudent2" resultMap="StudentTeacher2">select student.id,student.name,teacher.name tnamefrom teacher,studentwhere teacher.id=student.id</select><resultMap id="StudentTeacher2" type="Student"><result property="id" column="id"/><result property="name" column="name"/><association property="teacher" javaType="Teacher"><result property="name" column="tname"/></association></resultMap>

9.2 一对多的处理

  1. 环境搭建

    1. 实体类
    public class TeacherDouble {private int id;private String name;//一个老师拥有多个学生private List<Student> students;
    }@Data //getter和setter
    @AllArgsConstructor   //有参构造
    @NoArgsConstructor   //无参构造
    public class StudentSingle {private int id;private String name;private int tid;
    }
    
  2. 接口类

    public interface TeacherDoubleMapper {//获取老师List<TeacherDouble> getTeacher();//获取指定老师下的所有学生及老师的信息TeacherDouble getTeacher2(@Param("tid")int id);//TeacherDouble(id=1, name=贾老师, students=[StudentSingle(id=1, name=小蜜瓜, tid=1)])TeacherDouble getTeacher3(@Param("tid")int id);//TeacherDouble(id=0, name=贾老师, students=[StudentSingle(id=1, name=小蜜瓜, tid=1)])
    }
    
  3. Mapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper  namespace="com.jia.dao.TeacherDoubleMapper"><select id="getTeacher" resultType="com.jia.pojo.TeacherDouble">select * from teacher;</select><!--按照结果查询处理--><select id="getTeacher2" resultMap="TeacherStudent">select s.id sid,s.name sname,t.name tname,t.id tidfrom student s,teacher twhere s.tid=t.id and t.id=#{tid}</select><resultMap id="TeacherStudent" type="TeacherDouble"><result property="id" column="tid"/><result property="name" column="tname"/><!--复杂的属性,我们需要单独处理,对象:association  集合使用:collectionhavaType="" 指定属性的类型集合中的泛型信息,我们使用ofType获取--><collection property="students" ofType="StudentSingle"><result property="id" column="sid"/><result property="name" column="sname"/><result property="tid" column="tid"/></collection></resultMap><!--按照查询嵌套处理--><select id="getTeacher3" resultMap="TeacherStudent3">select * from teacher where id=#{tid}</select><resultMap id="TeacherStudent3" type="TeacherDouble"><!--一样的可以省略不写<result property="id" column="id"/>--><collection property="students" column="id" javaType="ArrayList"  ofType="StudentSinle" select="getStudentSingleById"/></resultMap><select id="getStudentSingleById" resultType="StudentSingle">select * from student where tid=#{tid}</select>
    </mapper>
    

    4数据库
    student:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S4MbJ1DD-1640586170015)(E:\Typroa笔记\MyBatis.assets\image-20211120173311345.png)]

    teacher:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Hqr9DKq-1640586170017)(E:\Typroa笔记\MyBatis.assets\image-20211120173251529.png)]

小结

  1. 关联 - association 多对一

  2. 集合-collection 一对多

  3. javaTyoe 和 ofType

    ​ javaType:用来指定实体类中属性的类型

    ​ ofType: 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

10.动态SQL

1.1 什么是动态SQL:

​ 动态SQL就是指根据不同的条件生成不同的SQL语句

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach
1.1.1 if
<select id="queryBlogIf" parameterType="map" resultType="blog">select * from mybatis.db1 where 1=1<if test="title != null">and title = #{title}</if><if test="content != null">and content = #{content}</if></select>
 HashMap map = new HashMap();map.put("title","1"); List<Bolg> bolgs = mapper.queryBlogIf(map);for (Blog blog:bolgs) {System.out.println(blog);}
1.1.2 choose、when、otherwise

不使用所有的条件,从多个条件中选择一个使用,类似于Java中的switch语句,如果没有条件,则所有都返回

<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG WHERE state = ‘ACTIVE’<where><choose><when test="title != null">AND title like #{title}</when><when test="author != null and author.name != null">AND author_name like #{author.name}</when><otherwise>AND featured = 1</otherwise></choose></where>
</select>
1.1.3 trim、where、set
<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG<where><if test="state != null">state = #{state}</if><if test="title != null">AND title like #{title}</if><if test="author != null and author.name != null">AND author_name like #{author.name}</if></where>
</select>

where元素只会在子元素返回任何内容的情况下插入“where”子句,若子句开头为:AMD/OR,where元素会将它移除掉

自定义 trim 元素来定制 where 元素的功能

<trim prefix="WHERE" prefixOverrides="AND |OR ">...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

动态set

<update id="updateAuthorIfNecessary">update Author<set><if test="username != null">username=#{username},</if><if test="password != null">password=#{password},</if><if test="email != null">email=#{email},</if><if test="bio != null">bio=#{bio}</if></set>where id=#{id}
</update>

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)

set 元素等价的自定义 trim 元素,覆盖了后缀值设置,并且自定义了前缀值

<trim prefix="SET" suffixOverrides=",">...
</trim>
1.1.4 SQL片段

有点时候,我们可能会将一些功能的部分抽取出来,方便复用;

  1. 使用SQL标签抽取公共的部分

    <sql id="if-title-author"><if test="title !=null">title = #{title}</if><if test="author != null">and author = #{author}</if></sql>
    
  2. 在需要使用的地方使用include标签引用即可

    <select id="queryBlogIF" parameterType="map" resultType="blog">select * from blog<where><include refid="if-title-author"></include></where></select>
    

    总体代码:

    <sql id="if-title-author"><if test="title !=null">title = #{title}</if><if test="author != null">and author = #{author}</if></sql><select id="queryBlogIF" parameterType="map" resultType="blog">select * from blog<where><include refid="if-title-author"></include></where></select>
    

    注意事项:

    • 最好基于单表来定义SQL片段
    • SQL片段中不要存在where标签
1.1.5 Foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)

<select id="selectPostIn" resultType="domain.blog.Post">SELECT *FROM POST PWHERE ID in<foreach item="item" index="index" collection="list"open="(" separator="," close=")">#{item}</foreach>
</select>

注意事项:foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 :你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

Service:

HashMap map = new HashMap();ArrayList<Integer> ids = new ArrayList<Integer>();ids.add(1);ids.add(2);ids.add(3);map.put("ids","ids");List<Blog> blogs = mapper.queryBlogForeach(map);for(Blog blog : blogs){System.out.println(blog);}

Mapper:

//查询第1-2-3号记录的博客  foreach测试List<Blog> queryBlogForeach(Map map);

mapper.xml:

<!--select * from mybatis.blog where 1=1 and (id=1 or id=2 or id=3)我们现在传递一个万能的map,这个map可以存在一个集合--><select id="queryBlogForeach" resultType="blog" parameterType="map">select * from mybatis.blog<where><foreach collection="ids" item="id" open = "and (" close=")" separator="or">id = #{id}</foreach></where></select>

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的形式,排序组合就行

11.缓存

查询 : 连接数据库 ,耗资源!

​ 一次查询的结果,给他暂存在一个可以直接取到的地方! —>内存 : 缓存

我们再次查询相同数据的时候,直接走缓存,就不用走数据库了

11.1.1 什么是缓存【Cache】
  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题
11.1.2 为什么使用缓存?

减少和数据库的交互次数,减少系统开销,提高系统效率

11.1.3 什么样的数据能使用缓存?

经常查询并且步经常改变的数据

11.1.4 Mybatis缓存
  • Mybatis包含一个非常强大的缓存特性,它可以非常方便地定制和配置缓存,缓存可以极大的提高擦好像效率。
  • Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
    • 默认情况下只开启一级缓存,(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
    • 为了提高扩展性,Mybatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存
11.1.5 一级缓存

默认情况下只开启一级缓存,(SqlSession级别的缓存,也称为本地缓存)

SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//第一次取
Student student = mapper.queryStudentById(1);
System.out.println(student);
Student student1 = mapper.queryStudentById(1);
System.out.println(student1);
System.out.println(student==student1);    //true  相同情况下第二次在缓存中取//这个区间是一级缓存sqlSession.close();

缓存失效的情况:

  1. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存!

  2. 查询不同的数据

  3. 查询不同的Mapper.xml

  4. 手动清理缓存:

    sqlSession.clearCache();//手动清理缓存
    

小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到连接关闭连接这个区间段,无法关闭****

11.1.6 二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以出现了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
  • 工作机制:一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中,如果当前会话关闭了,一级缓存中的数据就会被保存到二级缓存中,新的会话查询信息就可以从二级缓存中读取,不同的mapper查出的数据会放到自己对应的缓存(map)中

步骤

  1. 开启全局缓存
<!--显示的开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
  1. 在要使用二级缓存的Mapper中开启
<!--在当前mapper.xml中使用二级缓存--><cache/>
<!--也可以自定义参数-->
<cache eviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>

测试代码:

public void getStudent2(){SqlSession sqlSession = MybatisUtils.getSqlSession();SqlSession sqlSession2 = MybatisUtils.getSqlSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);StudentMapper mapper2 = sqlSession2.getMapper(StudentMapper.class);//第一次取Student student = mapper.queryStudentById(1);System.out.println(student);sqlSession.close();Student student2 = mapper2.queryStudentById(1);System.out.println(student2);//这个区间是一级缓存sqlSession2.close();System.out.println(student2==student);   //true}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PKP4w4TP-1640586170018)(E:\Typroa笔记\MyBatis.assets\image-20211130110639753.png)]

只进行了一次查询,第二次查询保存到了二级缓存中,直接取

报错问题:,在实体类中序列化

Caused by: java.io.NotSerializableException: com.jia.pojo.Student
/*** 多对一模型* lombok:相当于实体类中的getter和setter*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {private int id;private String name;private String tid;
}

小结:只要开启了二级缓存,在同一个Mapper下有效、所有的数据都会先放在一级缓存中、只有当会话提交或者关闭的时候,才会提交到二级缓存中

11.2.1 缓存原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-27CkTRnd-1640586170019)(E:\Typroa笔记\MyBatis.assets\image-20211130112654905.png)]

11.2.2 自定义缓存-enchace

Enchace是一种广泛使用的开源Jav啊分布式缓存,主要面向通用缓存

附录1 foreach与lambda表达式

        ArrayList<String> list = new ArrayList<>();list.add("b");list.add("a");list.add("d");list.forEach(item -> System.out.print(item));HashMap<String, String> map = new HashMap<>();map.put("1", "1");map.put("2", "2");map.put("3", "3");map.forEach((String key, String value) -> {System.out.println("key-->>" + key + "value--->>" + value);});List<Student> student = mapper.getStudent2();student.forEach(item-> {System.out.println(item);System.out.println("ok");});

附录2 left join on

SELECT * FROM teacher LEFT JOIN student ON teacher.id=student.tid
SELECT * FROM student LEFT JOIN teacher ON teacher.id=student.tid
SELECT a.,b.,c.* FROM user a
LEFT JOIN relevance b ON b.userId=a.userId
LEFT JOIN signature c ON c.signId=b.signId
WHERE a.orgnizationid=‘320923199604013026’;

附录3 面试高频

  • Mysql引擎
  • InnoDB底层
  • 索引
  • 索引优化

附录4 UUID简化

import org.junit.jupiter.api.Test;
import java.util.UUID;
@SuppressWarnings("all")   //抑制警告
public class IDutils {public static String getId(){return UUID.randomUUID().toString().replace("-","");}@Testpublic void test1(){System.out.println(IDutils.getId());//1cb458e9bfaf49ee9268ae26fd9678fe}
}

ring name;

private String tid;

}

小结:只要开启了二级缓存,在同一个Mapper下有效、所有的数据都会先放在一级缓存中、只有当会话提交或者关闭的时候,才会提交到二级缓存中

11.2.1 缓存原理

[外链图片转存中…(img-27CkTRnd-1640586170019)]

11.2.2 自定义缓存-enchace

Enchace是一种广泛使用的开源Jav啊分布式缓存,主要面向通用缓存

附录1 foreach与lambda表达式

        ArrayList<String> list = new ArrayList<>();list.add("b");list.add("a");list.add("d");list.forEach(item -> System.out.print(item));HashMap<String, String> map = new HashMap<>();map.put("1", "1");map.put("2", "2");map.put("3", "3");map.forEach((String key, String value) -> {System.out.println("key-->>" + key + "value--->>" + value);});List<Student> student = mapper.getStudent2();student.forEach(item-> {System.out.println(item);System.out.println("ok");});

附录2 left join on

SELECT * FROM teacher LEFT JOIN student ON teacher.id=student.tid
SELECT * FROM student LEFT JOIN teacher ON teacher.id=student.tid
SELECT a.,b.,c.* FROM user a
LEFT JOIN relevance b ON b.userId=a.userId
LEFT JOIN signature c ON c.signId=b.signId
WHERE a.orgnizationid=‘320923199604013026’;

附录3 面试高频

  • Mysql引擎
  • InnoDB底层
  • 索引
  • 索引优化

附录4 UUID简化

import org.junit.jupiter.api.Test;
import java.util.UUID;
@SuppressWarnings("all")   //抑制警告
public class IDutils {public static String getId(){return UUID.randomUUID().toString().replace("-","");}@Testpublic void test1(){System.out.println(IDutils.getId());//1cb458e9bfaf49ee9268ae26fd9678fe}
}

MyBatis原理及搭建教程相关推荐

  1. Spring+SpringMVC+Mybatis框架集成搭建教程

    一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...

  2. Spring+SpringMvc+Mybatis框架集成搭建教程二(依赖配置及框架整合)

    依赖导入以及框架整合 (1).打开项目的pom.xml文件,声明依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" x ...

  3. MyBatis框架的搭建以及使用教程

    MyBatis文章目录 Mybatis框架的搭建以及使用教程 目录 MyBatis文章目录 前言 一.Mybatis框架搭建步骤 第一步:准备工作 1.下载并添加MyBatis依赖包 2.创建数据库表 ...

  4. Spring Cloud 5分钟搭建教程

    1.前言: 1.1.以下内容是我通过阅读官方文档,并成功实践后的经验总结,希望能帮助你更快地理解和使用Spring Cloud. 1.2.默认读者已经熟练掌握Spring 全家桶,Spring Boo ...

  5. python任务调度平台 界面_分布式任务调度平台XXL-JOB搭建教程

    关于分布式任务调度平台XXL-JOB,其实作者 许雪里在其发布的中文教程中已经介绍的很清楚了,这里我就不做过多的介绍了,关于其搭建教程,本人依照其文档搭建起来基本上也没遇到啥问题,这里通过博客的形式记 ...

  6. Spring Cloud 5分钟搭建教程(附上一个分布式日志系统项目作为参考)

    Spring Cloud 5分钟搭建教程(附上一个分布式日志系统项目作为参考) 上面是我基于Spring Cloud ,Spring Boot 和 Docker 搭建的一个分布式日志系统. 目前已在我 ...

  7. Redis集群的原理和搭建

    Redis集群的原理和搭建 前言 Redis 是我们目前大规模使用的缓存中间件,由于它强大高效而又便捷的功能,得到了广泛的使用.单节点的Redis已经就达到了很高的性能,为了提高可用性我们可以使用Re ...

  8. 企业级内网的域控环境搭建教程

    所谓域控就是一台或多台域控制器能够控制域内的其他服务器,可实现统一更换电脑桌面,统一修改密码等诸多操作,就像网吧里的网络结构一样,只不过更复杂,更庞大,下面是详细部署教程 说明:要做这个实验需要模拟内 ...

  9. 阿里云服务器ECS接入多IP_ECS绑定多个弹性公网IP搭建教程

    很多场景下我们需要单服务器多IP来完成业务需求,运营商们大多采取单独出售ip来满足客户需求,当然相对靠谱的运营商是我们的首选,下面介绍一下阿里云ECS部署多IP是如何实现的. 1.选择云服务器ECS ...

最新文章

  1. python moviepy textclip中文_用Python玩转视频剪辑,秀的飞起!
  2. 联结你与万物的8种元素
  3. redis企业级应用(下)-如何维护redis的key
  4. 为何大多数人做出来的图表只是一坨屎?
  5. python关闭读写的所有的文件-python文件读写操作
  6. 最新的ndkr20编译c_史上最优雅的NDK加载pass方案
  7. Cannot resolve symbol ‘NotBlank‘ Cannot resolve symbol ‘Email‘ Cannot resolve symbol ‘NotEmpty‘
  8. JavaFX官方教程(十一)之动画基础
  9. idea 新建的java项目没发run_IntelliJ IDEA创建普通的Java 项目及创建 Java 文件并运行的教程...
  10. form表单提交,后台实体类接收转义问题
  11. 2.图像作为函数 | 图像的量化、大小、类型、位置以及Matlab使用_4
  12. flink 1.9.0 编译:flink-fs-hadoop-shaded 找不到
  13. [PAT A1043]Is is a Binary Search Tree
  14. Dubbo概述及架构图
  15. 非容器化jenkins 连接k8s 集群
  16. 特征:什么是特征和特征选择?
  17. android studio distributionurl是干嘛的,不懂就学系列(一):gradle配置本地distributionUrl...
  18. 分组查询最新的一条记录
  19. [leetcode/lintcode 题解] 谷歌面试题:基因相似度
  20. mit计算机科学中心,MIT苏珊•霍克菲尔德校长在清华大学-麻省理工学院-香港中文大学“理论计算机科学研究中心”揭牌典礼上的致辞...

热门文章

  1. 教妹学Java(十九):continue 关键字详解
  2. NE555芯片知识应用讲解
  3. 2022年数模国赛冲刺之模型复习2
  4. 在Ubuntu中设置中文输入法
  5. 第一招:考拉网,菜鸟的市场就是蓝海
  6. linux dstat 监控mysql_linux命令---dstat强大的性能监测工具(通用的系统资源统计工具:可以实时的监控cpu、磁盘、网络、IO、内存等使用情况。)...
  7. 【百度地图(极度真实版)---HTML实现(附 效果+源代码)】
  8. 愤怒的小鸟和人类对抛物线的迷恋
  9. SAP 最详细的批次管理解释和配置过程
  10. C语言实现split()函数:字符串分割