首页 > 其他分享 >持续性学习-Day19(MyBatis)

持续性学习-Day19(MyBatis)

时间:2024-06-20 18:00:24浏览次数:10  
标签:mapper 缓存 UserMapper 持续性 id sqlSession user MyBatis Day19

MyBatis

参考:https://www.w3cschool.cn/mybatis3/mybatis3-rhna3ndr.html

环境:

  • JDK

  • MySQL

  • Maven

  • IDEA

1、简介

1.1 什么是MyBatis

  • MyBatis 是一款优秀的持久层框架

  • 它支持自定义 SQL、存储过程以及高级映射。

  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和POJO(Plain Ordinary Java Object,简单的Java对象)为数据库中的记录。

1.2 持久划

数据持久化

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

  • 内存:断电即失

  • 数据库(JDBC),IO文件持久化。

1.3 持久层

  • 完成持久化工作的代码

  • 层界限十分明显

2、第一个MyBatis程序

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

新建项目:

  1. 新建一个普通maven项目

  2. 删除src目录

  3. 导入maven依赖

创建一个module

  1. 编写MyBatis的核心配置文件

<configuration>
   <environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="com.mysql.cj.jdbc.Driver"/><!--${driver}-->
               <property name="url" value="jdbc:mysql://localhost:3306/school?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/><!--${url}-->
               <property name="username" value="root"/><!--${username}-->
               <property name="password" value="stujc0828"/><!--${password}-->
           </dataSource>
       </environment>
   </environments>
   <mappers>
       <mapper resource="com/stujc/dao/UserMapper.xml"/>
   </mappers>
</configuration>
  1. 编写MyBatis工具类

    public class MyBatisUtil {
       private static SqlSessionFactory sqlSessionFactory;
       static {
           try {
               String resource = "mybatis-config.xml";
               InputStream inputStream = Resources.getResourceAsStream(resource);
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
          } catch (Exception e) {
               throw new RuntimeException(e);
          } finally {
          }
      }

       public static SqlSession getSqlSession(){
           return sqlSessionFactory.openSession();
      }
    }
  2. 编写代码

  • 实体类

  • Dao接口

    • public interface UserDao {
         List<User> getUserList();
      }
  • 接口实现类

    • <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
             PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.stujc.dao.UserDao">
         <select id="getUserList" resultType="com.stujc.pojo.User">
            select * from student s
            /*select * from Blog where id = #{id}*/
         </select>
      </mapper>
  1. 测试

public class UserDaoTest {
  @Test
  public void test(){
      SqlSession sqlSession = MyBatisUtil.getSqlSession();
      try {
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          List<User> userList = mapper.getUserList();
          for (User user : userList) {
              System.out.println(user);
          }
      } catch (Exception e) {
          e.printStackTrace();
      } finally {
          sqlSession.close();
      }
  }
}

3、CRUD

选择,查询语句

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

  • resultType:SQL语句执行的返回值

  • parameterType:参数类型

  1. 编写接口

public interface UserMapper {
   //查询全部用户
   List<User> getUserList();
   //根据id查询用户
   User getUserById(int id);
   //插入一个用户
   int insertUser(User user);
   //修改用户
   int updateUser(User user);
   //删除用户
   int deleteUser(int id);
}
  1. 编写mapper中对应的sql语句

<mapper namespace="com.stujc.dao.UserMapper">
   <select id="getUserList" resultType="com.stujc.pojo.User">
      select * from users;
   </select>
   <select id="getUserById" resultType="com.stujc.pojo.User" parameterType="int">
      select * from users where id = #{id};
   </select>
   <insert id="insertUser" parameterType="com.stujc.pojo.User">
      insert into users (id,name,password,email,birthday) values (#{id},#{name},#{password},#{email},#{birthday});
   </insert>
   <update id="updateUser" parameterType="com.stujc.pojo.User">
      update users set name = #{name} where id = #{id};
   </update>
   <delete id="deleteUser" parameterType="int">
      delete from users where id = #{id};
   </delete>
</mapper>
  1. 测试

  • 注意点:增删改需要提交事务

public class UserDaoTest {
   @Test
   public void test(){
       SqlSession sqlSession = MyBatisUtil.getSqlSession();
       try {
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           List<User> userList = mapper.getUserList();
           for (User user : userList) {
               System.out.println(user);
          }
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }

   @Test
   public void test1(){
       SqlSession sqlSession = MyBatisUtil.getSqlSession();
       try {
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           User user = mapper.getUserById(1);
           System.out.println("test1:"+user);
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }

   @Test
   public void test2(){
       SqlSession sqlSession = MyBatisUtil.getSqlSession();
       try {
           User user = new User(4,"zhaoliu","123456","[email protected]",java.sql.Date.valueOf("1980-12-04"));
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           int i = mapper.insertUser(user);
           System.out.println("test2:"+i);
           sqlSession.commit();
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }

   @Test
   public void test3(){
       SqlSession sqlSession = MyBatisUtil.getSqlSession();
       try {
           User user = new User(4,"田七","123456","[email protected]",java.sql.Date.valueOf("1980-12-04"));
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           int i = mapper.updateUser(user);
           System.out.println("test3:"+i);
           sqlSession.commit();
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }

   @Test
   public void test4(){
       SqlSession sqlSession = MyBatisUtil.getSqlSession();
       try {
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           int i = mapper.deleteUser(4);
           System.out.println("test3:"+i);
           sqlSession.commit();
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           sqlSession.close();
      }
  }
}

4、配置解析

4.1 核心配置文件

  • mybatis-config.xml

4.2 环境配置

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

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

MyBatis默认的事务管理器就是JDBC,连接池:POOLED

4.3 属性(Properties)

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

  • 编写配置文件

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/school?useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=stujc0828
  • 在核心配置文件中引入

<!--引入外部配置文件-->
<properties resource="db.properties"/>

4.4 类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字

  • 意在降低冗余的全限定类名书写

<typeAliases>
    <typeAlias type="com.stujc.pojo.User" alias="User"/>
</typeAliases>
  • 也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

<!--默认别名class首字母小写-->
<package name="com.stujc.pojo"/>
  • 若有注解,则别名为其注解值

 @Alias("author")

4.5 设置

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

4.6 映射器(mappers)

方式一

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>	
</mappers>

4.7 生命周期和作用域

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

5、ResultMap

解决属性名和字段名不一致的问题

<resultMap id="UserMap" type="User">
	<!--column数据库中的字段,property实体类中的属性-->
	<result column="" property=""/>
</resultMap>
<select id="getUserById" resultMap="UserMap" parameterType="int">
	select * from users where id = #{id};
</select>

6、日志

6.1 日志工厂

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

logImpl:

  • SLF4J

  • LOG4J(deprecated since 3.5.9)

  • LOG4J2

  • JDK_LOGGING

  • COMMONS_LOGGING

  • STDOUT_LOGGING (标准日志输出)

  • NO_LOGGING

在MyBatis中,具体使用哪一个,在设置中设定

<!--设置-->
<settings>
   <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
Opening JDBC Connection
Created connection 365590665.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@15ca7889]
==> Preparing: select * from users;
==> Parameters:
<==   Columns: id, name, password, email, birthday
<==       Row: 1, zhangsan, 123456, [email protected], 1980-12-04
<==       Row: 2, lisi, 123456, [email protected], 1981-12-04
<==       Row: 3, wangwu, 123456, [email protected], 1979-12-04
<==       Row: 4, 田七, 123456, [email protected], 1980-12-04
<==     Total: 4
User{id=1, name='zhangsan', password='123456', email='[email protected]', birthday=Thu Dec 04 00:00:00 CST 1980}
User{id=2, name='lisi', password='123456', email='[email protected]', birthday=Fri Dec 04 00:00:00 CST 1981}
User{id=3, name='wangwu', password='123456', email='[email protected]', birthday=Tue Dec 04 00:00:00 CST 1979}
User{id=4, name='田七', password='123456', email='[email protected]', birthday=Thu Dec 04 00:00:00 CST 1980}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@15ca7889]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@15ca7889]
Returned connection 365590665 to pool.

6.2 Log4J

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

  2. 可以控制每一条日志的输出格式

  3. 通过定义每一条日志的级别,能够更加细致的控制日志的生成过程

  4. 通过一个配置文件灵活的进行配置,不需要修改应用的代码

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.20.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.20.0</version>
        </dependency>

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- log4j2 配置文件 -->
<!-- 日志级别 trace<debug<info<warn<error<fatal -->
<configuration status="debug">
    <!-- 自定义属性 -->
    <Properties>
        <!-- 日志格式(控制台) -->
        <Property name="pattern1">[%-5p] %d %c - %m%n</Property>
        <!-- 日志格式(文件) -->
        <Property name="pattern2">
            =========================================%n 日志级别:%p%n 日志时间:%d%n 所属类名:%c%n 所属线程:%t%n 日志信息:%m%n
        </Property>
        <!-- 日志文件路径 -->
        <Property name="filePath">F:\logs/myLog.log</Property>
    </Properties>

    <appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${pattern1}"/>
        </Console>
        <RollingFile name="RollingFile" fileName="${filePath}"
                     filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="${pattern2}"/>
            <SizeBasedTriggeringPolicy size="5 MB"/>
        </RollingFile>
    </appenders>
    <loggers>
        <root level="debug">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFile"/>
        </root>
    </loggers>
</configuration>

7、分页

<!--分页查询用户-->
<select id="getUserByLimit" resultType="User" parameterType="map">
  select * from users limit #{startIndex},#{pageSize}
</select>
<!--分页查询用户2-->
<select id="getUserByRowBounds" resultType="User">
  select * from users;
</select>
@Test
public void getUserByLimit(){
   SqlSession sqlSession = MyBatisUtil.getSqlSession();
   try {
       Map<String,Integer> map = new HashMap<String,Integer>();
       map.put("startIndex",0);
       map.put("pageSize",2);
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       List<User> userList = mapper.getUserByLimit(map);
       for (User user : userList) {
           System.out.println(user);
      }
  } catch (Exception e) {
       e.printStackTrace();
  } finally {
       sqlSession.close();
  }
}

@Test
public void getUserByRowBounds(){
   SqlSession sqlSession = MyBatisUtil.getSqlSession();
   try {
       RowBounds rowBounds = new RowBounds(1,2);
       List<User> userList = sqlSession.selectList("com.stujc.dao.UserMapper.getUserByRowBounds",null, rowBounds);
       for (User user : userList) {
           System.out.println(user);
      }
  } catch (Exception e) {
       e.printStackTrace();
  } finally {
       sqlSession.close();
  }
}

8、注解开发

8.1 面向接口编程

关于接口的理解

  • 接口从更深层次的理解,应是定义(规范、约束)与实现(名实分离的原则)的分离

  • 接口的本身反映了系统设计人员对系统的抽象理解

  • 接口应有两类:

    • 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class)

    • 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface)

    一个个体有可能有多个抽象面。抽象体与抽象面是有区别的

8.2 使用注解开发

  1. 注解在接口上实现

    public interface UserMapper {
        @Select("select * from users")
        List<User> getUserList();
    
        //方法存在多个参数,所有的参数前面必须加上@Param()注解
        @Select("select * from users where id = #{id} and name = #{name}")
        User getUserByID(@Param("id") int id,@Param("name") String name);
    }
    
  2. 需要再核心文件中绑定接口

    <mappers>
       <mapper class="com.stujc.dao.UserMapper"/>
    </mappers>
  3. 测试

    @Test
    public void getUserList(){
       SqlSession sqlSession = MyBatisUtil.getSqlSession();
       //底层主要应用反射
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       List<User> userList = mapper.getUserList();
       for(User user : userList){
           System.out.println(user);
      }
       sqlSession.close();
    }

本质:反射机制实现

底层:动态代理

9、LomBox

@Getter and @Setter @FieldNameConstants @ToString @EqualsAndHashCode @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog @Data @Builder @SuperBuilder @Singular @Jacksonized @Delegate @Value @Accessors @Tolerate @Wither @With @SneakyThrows

10、缓存

什么是缓存

  1. 存在内存中的临时数据

  2. 将用户经常查询的数据放在缓存(内存)中,用户去查数据就不用从磁盘上查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题

为什么使用缓存

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

什么样的数据能使用缓存

  • 经常查询且不经常改变的数据

10.1 mybatis缓存

Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存

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

  • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存

  • 为了提高扩展性,Mybatis定义了缓存接口Cache,可以通过实现Cache接口来自定义二级缓存

10.2 一级缓存

测试步骤

  1. 开启日志

  2. 测试在一个SqlSession中查询两次相同的记录

  3. 查看日志输出

一级缓存是默认开启的,只在一次SqlSession中有效。

一级缓存就是一个map

10.3 二级缓存

 

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存

  • 工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中

    • 如果会话关闭了,这个会话对应的一级缓存就没了;想要实现的效果是,会话关闭了,一级缓存中的数据被保存到二级缓存中

    • 新的会话查询信息,就可以从二级缓存中获取内容

    • 不同的mapper查出的数据会放在自己对应的缓存(map)中

步骤:

  1. 开启全局缓存

<!--显示的开启全局缓存-->
<setting name="cacheEnabled" value="true"/>
  1. 在要使用二级缓存的Mapper中开启

   <cache
    eviction="FIFO"
    flushInterval="60000"
    size="512"
    readOnly="true"/>
  1. 测试

    1. 问题:需要将实体类序列化,否则会报错

10.4 自定义缓存

Ehcache是一种广泛使用的开源Java分布式缓存,主要面向通用缓存
<?xml version="1.0" encoding="UTF-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false">
   <!--
       diskStore:缓存路径,ehcache分为内存和磁盘两极,此属性定义磁盘的缓存位置
       user.home - 用户主目录
       user.dir - 用户当前工作目录
       java.io.tmdir - 默认临时文件路径
   -->
   <diskStore path="./tmpdir/Tmp_EhCache"/>

   <defaultCache eternal="false"
                 maxElementsInMemory="10000"
                 overflowToDisk="false"
                 diskPersistent="false"
                 timeToIdleSeconds="1800"
                 timeToLiveSeconds="259200"
                 memoryStoreEvictionPolicy="LRU"/>
   
   <cache name="cloud_user"
          eternal="false"
          maxElementsInMemory="5000"
          overflowToDisk="false"
          diskPersistent="false"
          timeToIdleSeconds="1800"
          timeToLiveSeconds="1800"
          memoryStoreEvictionPolicy="LRU"/>
   <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略,只能定义一个
   -->
   <!--
       name:缓存名称
       maxElementsInMemory:缓存最大数目
       maxElementsOnDisk:硬盘最大缓存个数
       external:对象是否永久有效,一旦设置了,timeout将不起作用
       overflowToDisk:是否保存到磁盘,当系统宕机时
   -->
</ehcache>
<!--mapper-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

 

MyBatis加载机制

  1. Resources获取全局配置文件

  2. 实例化SqlSessionFactoryBuilder构造器

  3. 解析配置文件流XmlConfigBuilder

  4. Configuration所有的配置信息

  5. SqlSessionFactory实例化

  6. transaction事务管理

  7. 创建executor执行器

  8. 创建sqlsession

  9. 实现CRUD,查看执行结果

  10. 提交事务,关闭

  11.  

 

 

 

 

 

标签:mapper,缓存,UserMapper,持续性,id,sqlSession,user,MyBatis,Day19
From: https://www.cnblogs.com/-Gin/p/18259196

相关文章

  • 窥探Mybatis配置到执行源码剖析
    mybatis自动配置过程首先我们项目中使用mybatis如果是mybatis的话会引入依赖<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</ve......
  • mybatisplus代码生成
    1.引入依赖点击查看代码<!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.......
  • MyBatis批量插入不用foreach
    原文链接:MyBatis批量插入不用foreach–每天进步一点点(longkui.site)近日,项目中有一个耗时较长的Job存在CPU占用过高的问题,经排查发现,主要时间消耗在往MyBatis中批量插入数据。mapperconfiguration是用foreach循环做的,差不多是这样。(由于项目保密,以下代码均为自己手写的demo......
  • MyBatis
    MyBatis1、MyBatis是什么框架?MyBatis是一个持久层框架,它是Java编程语言中用于操作关系型数据库的一个工具。MyBatis的主要作用是简化数据库访问的过程,提供了一种方便、灵活的方式来进行SQL操作。相比传统的JDBC编程方式,MyBatis可以更加高效地管理数据库连接、执行SQL......
  • mybatis-mp 高级用法:ORM+SQL模板,真正意义实现ORM!!!
    官网:mybatis-mp.cn目前ORM以JPAPLUS为首的ORM,遇到稍微复杂的、或者数据库特性函数时通常需要自己写sql,或代码中,或xml中,这就有点难受了1:有没有好的办法?mybatis-mp的做法就是ORM+SQL模板,SQL模板不仅仅是sql字符串,它还帮你替换关系的信息:列SysUserRo......
  • Mybatis的Mapper中方法入参什么时候加@Param
    参数情况:一个基本类型--不需要多个基本类型--需要一个对象 --不需要多个对象  --不需要一个集合  --不需要 单个基本类型不用加@ParamMapper接口方法:voiddeleteUserById(LonguserId);XML中的SQL语句:<deleteid="deleteUserById"parameterType=......
  • MybatisPlus之继承IService
    有一些简简单单的数据库增删改查还需要Service到Mapper一步步地来吗?答案是否定地,甚至代码都不用实现哦。这就是因为IService接口提供了一些基础功能的实现IService和ServiceImplIService只是一个接口,它并不能实现功能,如果你的service的接口继承它,继承过来的只是接口没有功......
  • MyBatis之ResultMap
    ResultMap的属性列表 resultMap标签介绍constructor-用于在实例化类时,注入结果到构造方法中idArg-ID参数;标记出作为ID的结果可以帮助提高整体性能arg-将被注入到构造方法的一个普通结果id–一个ID结果;标记出作为ID的结果可以帮助提高整体性能,用于主键......
  • MyBatis Plus Generator代码生成
    一、MyBatisPlusGeneratorMyBatisPlus是一个功能强大的持久层框架,它简化了MyBatis的使用,提供了许多便捷的功能。其中,MyBatisPlusGenerator是一个强大的代码生成器,可以帮助我们快速地根据数据库表结构生成对应的实体类、映射文件和DAO接口。在MyBatisPlusGenerator中......
  • mybatis关联查询
    packagecom.xin.pojo;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importjava.util.List;@Data@AllArgsConstructor@NoArgsConstructorpublicclassUserLogin{privateintid;privateStringusername;......