Mybatiss

Mybatis

Springboot整合mybatis

链接: Springboot整合mybatis

一.第一个Mybatis程序

用Maven来搭建:
链接: Mybatis参考手册.

第一步导入依赖:
 <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

    </dependencies>
    <!--资源导出问题的,解决方法-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

第二步:配置mybatis-config.xml

数据库时区问题!
url: jdbc:mysql://localhost:3306/db_film?serverTimezone=UTC

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/tian/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

第三步:新建一个Utils通用的类用来创建SqlSession对象

package com.tian.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;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    public static SqlSession getSqlSession(){
       return sqlSessionFactory.openSession();
    }
}

第四步:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二.注意

  • 资源导出问题(放在java里的配置文件要导出的话,在pom.xml中配置)
<build>
       <resources>
           <resource>
               <directory>src/main/java</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>false</filtering>
           </resource>
       </resources>
   </build>

Junit测试

方式一:

package com.tian.mapper;

import com.tian.pojo.User;
import com.tian.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserTest {
  @Test
  public void test(){
      //获取sqlSession对象
      SqlSession sqlSession = MybatisUtils.getSqlSession();
      //匹配Mapper并执行xml中的sql语句,返回结果,
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      List<User> allUser = mapper.getAllUser();
      //遍历
      for (User user : allUser) {
          System.out.println(user);
      }
      //关闭资源
      sqlSession.close();
  }

}

三.CRUD

增删改必须要提交事务
sqlSession.commit();

1.select

在这里插入图片描述
1.编写接口
在这里插入图片描述

2.编写对应的mapper中的sql语句
在这里插入图片描述

3.测试

 @Test
    public void test01(){
        //获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //匹配Mapper并执行xml中的sql语句,返回结果
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userByID = mapper.getUserByID(1);
        System.out.println(userByID.toString());
        //提交事务
        sqlSession.commit();
        //关闭资源
        sqlSession.close();
    }
   

增删改一定要提交事务: sqlSession.commit();

2.insert

同上

3.update

同上

4.delete

同上

四.万能的Map

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

//万能的Map
   public int insertUser(Map<String,Object> map);
 <insert id="insertUser" parameterType="map">
       insert into user (id,name,pwd) values (#{userid},#{username},#{userpwd})
   </insert>
@Test
   public void test02(){
       //获取sqlSession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       //匹配Mapper并执行xml中的sql语句,返回结果
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       Map<String, Object> map = new HashMap<String, Object>();

       map.put("userid",5);
       map.put("username","123");
       map.put("userpwd","456");

       int i = mapper.insertUser(map);
       System.out.println(i);
       //提交事务
       sqlSession.commit();
       //关闭资源
       sqlSession.close();
   }
  • Map传递参数,直接在sql中取出key即可!【parameterType=“map”】

  • 对象传递参数,直接在sql中取对象的属性即可!【parameterType=“Object”】

  • 只有一个基本类型参数的情况下,可以直接在sql中取到!
    多个参数用Map,或者注解!

模糊查询怎么写?

  • 1.Java代码执行的时候,传递通配符% %

List userList = mapper.getuserLike(“%李%”");

  • 2.在sql拼接中使用通配符!

select * from mybatis.user where name like “%”#{value}“%”
javal

五.配置解析

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

  • mybatis-config.xml

configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

环境配置(environments)

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

不过要记住:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境。

学会使用配置多套运行环境!

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

核心文件配置

mybatis-config.xml

Mybatis的配置文件包含了深深影响MyBatis行为的设置和属性信息。
属性优化
1.外部新建一个mybatis.properties文件

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

2.引入外部文件

<properties resource="mybatis.properties"></properties>

可以在其中增加一些属性配置

如果两个文件有同一字段,优先使用外部配置文件!

类型别名(typeAliases)

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

<typeAliases>
   <typeAlias type="com.Long.pojo.User" alias="user"/>
</typeAliases>

2.也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

<typeAliases>
       <package name="com.Long.pojo"/>
   </typeAliases>

3.每一个在包 com.Long 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 com.Long.hello 的别名为 hello;若有注解,则别名为其注解值。

@Alias("hello")
<select id="selectUser" resultType="hello">
SELECT * FROM mybatis.user
</select>

设置(settings)

mybatis极为重要的调整设置,他们会改变Mybatis的运行时行为
在这里插入图片描述

其他设置

  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
    mybatis-generator-core
    mybatis-plus
    通用mapper

映射器(mappers)

文档中提供4种,常用方式一
MapperRegistry:注册绑定我们的Mapper文件(类似于接口实现类)
方式一:

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="com/Long/dao/UserMapper.xml"/>
</mappers>

方式二:

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
   <mapper class="com.Long.dao.UserMapper"/>
</mappers>

注意点:

接口和他的Mapper配置文件必须同名!
接口和他的Mapper配置文件必须在同一个包下!

六.生命周期和作用域

在这里插入图片描述
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
在这里插入图片描述
这里面的每一个Mapper,就代表一个具体的业务!

SqlSessionFactoryBuilder:

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

SqlSessionFactory:

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

SqlSession:

  • 连接到连接池的一个请求!
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完赶快关闭,否则资源被占用。

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

数据库中的字段

新建一个项目,拷贝之前,测试实体字段不一致的情况

User

package com.hou.pogo;

public class User {

   private int id;
   private String name;
   private String password;
}

问题:

User{id=2, name=‘wang’, password=‘null’}

解决方法:

核心配置文件

  • 起别名
<select id="getUserById" resultType="User"
   parameterType="int">
       select id,name,pwd as password from mybatis.user where id = #{id}
</select>
  • resultMap 结果集映射
<?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">
<!--namespace绑定一个对应的mapper接口-->
<mapper namespace="com.hou.dao.UserMapper">

   <select id="getUserById" resultMap="UserMap" parameterType="int">
       select * from mybatis.user where id = #{id}
   </select>

   <!--结果集映射-->
   <resultMap id="UserMap" type="User">
       <!--colunm 数据库中的字段,property实体中的属性-->
       <result column="id" property="id"></result>
       <result column="name" property="name"></result>
       <result column="pwd" property="password"></result>
   </resultMap>

</mapper>
  • resultMap 元素是 MyBatis 中最重要最强大的元素。

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

<resultMap id="UserMap" type="User">
   <!--colunm 数据库中的字段,property实体中的属性-->
   <!--<result column="id" property="id"></result>-->
   <!--<result column="name" property="name"></result>-->
   <result column="pwd" property="password"></result>
</resultMap>

七.日志

如果一个数据库操作,出现了异常,那么日志是最好的排错助手!

主要:

  • STDOUT_LOGGING

  • lo4j

1…导入依赖

<dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
</dependency>

2.写配置文件

3.配置log4j为日志的实现

4.log4j的使用

简单使用
1.在要使用的log4j类中,导入import org.apache.log4j.Logger;
2.日志对象,参数为当前类的class
3.日志级别
1.info
2.debug

3.error

<!--配置日志-->
   <settings>
       <setting name="logImpl" value="STDOUT_LOGGING"/>
   </settings>

Log4j

先导包

pom.xml下

<dependencies>
   <!-- https://mvnrepository.com/artifact/log4j/log4j -->
   <dependency>
       <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
       <version>1.2.17</version>
   </dependency>
</dependencies>

新建log4j.properties文件

### set log levels ###
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/hou.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

配置实现

<settings>
   <setting name="logImpl" value="LOG4J"/>
</settings>

Log4j使用

package com.hou.dao;

import com.hou.pojo.User;
import com.hou.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;

public class UserDaoTest {

   static Logger logger = Logger.getLogger(UserDaoTest.class);

   @Test
   public void test(){
       // 获得sqlsession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       try{
           // 1.执行 getmapper
           UserMapper userDao = sqlSession.getMapper(UserMapper.class);
           logger.info("测试");
           User user = userDao.getUserById(2);
           System.out.println(user);
       }catch(Exception e){
           e.printStackTrace();
       }finally{
           //关闭
           sqlSession.close();
       }
   }

   @Test
   public void testLog4j(){
       logger.info("info:进入了testlog4j");
       logger.debug("debug:进入了testlog4j");
       logger.error("error:进入了testlog4j");
   }

}

八.分页

用处:减少数据的处理量
xml

<?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">
<!--namespace绑定一个对应的mapper接口-->
<mapper namespace="com.hou.dao.UserMapper">

  <select id="getUserById" resultMap="UserMap"
  parameterType="int">
      select * from mybatis.user where id = #{id}
  </select>

  <!--结果集映射-->
  <resultMap id="UserMap" type="User">
      <!--colunm 数据库中的字段,property实体中的属性-->
      <!--<result column="id" property="id"></result>-->
      <!--<result column="name" property="name"></result>-->
      <result column="pwd" property="password"></result>
  </resultMap>

  <select id="getUserByLimit" parameterType="map"
          resultType="User" resultMap="UserMap">
    select * from mybatis.user limit #{startIndex},#{pageSize}
  </select>

</mapper>

java测试:

//    limit实现分页查询
   @Test
   public void  test6(){
       //        通过工具类获取sqlSession对象
       SqlSession sqlSession = utils.getSession();
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       HashMap<String, Integer> map = new HashMap<String, Integer>();
       map.put("startIndex",0);
       map.put("pageSize",2);
       List<User> userList = mapper.getlimit(map);
       for (User USER:userList
       ) {
           System.out.println(USER);
       }
       //        关闭sqlSession对象(避免内存泄漏)
       sqlSession.close();
   }

RowBounds分页

@Test

@Test
public void getUserByRow(){
   SqlSession sqlSession = MybatisUtils.getSqlSession();
   //RowBounds实现
   RowBounds rowBounds = new RowBounds(1, 2);

   //通过java代码层面
   List<User> userList = sqlSession.selectList
       ("com.hou.dao.UserMapper.getUserByRowBounds",
        null,rowBounds);

   for (User user : userList) {
       System.out.println(user);
   }

   sqlSession.close();
}
  1. 分页插件
  • pageHelper

九.注解开发

1.删除 UserMapper.xml

2.UserMapper

package com.hou.dao;

import com.hou.pojo.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper {

   @Select("select * from user")
   List<User> getUsers();
}

3.核心配置 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
       PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

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

   <!--可以给实体类起别名-->
   <typeAliases>
       <typeAlias type="com.hou.pojo.User" alias="User"></typeAlias>
   </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 class="com.hou.dao.UserMapper"></mapper>
   </mappers>
</configuration>

本质:反射机制

底层:动态代理!

Mybatis详细执行流程:

1.Resource获取全局配置文件

2.实例化SqlsessionFactoryBuilder

3.解析配置文件流XMLCondigBuilder

4.Configration所有的配置信息

5.SqlSessionFactory实例化

6.trasactional事务管理

7.创建executor执行器

8.创建SqlSession

9.实现CRUD

10.查看是否执行成功

11.提交事务

12.关闭

注解CRUD

package com.hou.dao;

import com.hou.pojo.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface UserMapper {

   @Select("select * from user")
   List<User> getUsers();

   //方法存在多个参数,所有的参数必须加@Param
   @Select("select * from user where id = #{id}")
   User getUserById(@Param("id") int id);

   @Insert("insert into user (id, name, pwd) values" +
           "(#{id},#{name},#{password})")
   int addUser(User user);

   @Update("update user set name=#{name}, pwd=#{password} " +
           "where id=#{id}")
   int updateUser(User user);

   @Delete("delete from user where id=#{id}")
   int deleteUser(@Param("id") int id);

}

注解CRUD

package com.hou.dao;

import com.hou.pojo.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface UserMapper {

   @Select("select * from user")
   List<User> getUsers();

   //方法存在多个参数,所有的参数必须加@Param
   @Select("select * from user where id = #{id}")
   User getUserById(@Param("id") int id);

   @Insert("insert into user (id, name, pwd) values" +
           "(#{id},#{name},#{password})")
   int addUser(User user);

   @Update("update user set name=#{name}, pwd=#{password} " +
           "where id=#{id}")
   int updateUser(User user);

   @Delete("delete from user where id=#{id}")
   int deleteUser(@Param("id") int id);

}

MybatisUtile

package com.hou.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
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();
       }
   }

   public static SqlSession getSqlSession(){
       return sqlSessionFactory.openSession(true);//设置自动提交事务true
   }

}

Test

package com.hou.dao;

import com.hou.pojo.User;
import com.hou.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {

   @Test
   public void test(){
       // 获得sqlsession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       try{
           // 1.执行 getmapper
           UserMapper userDao = sqlSession.getMapper(UserMapper.class);
           List<User> userList = userDao.getUsers();
           for (User user : userList) {
               System.out.println(user);
           }

       }catch(Exception e){
           e.printStackTrace();
       }finally{
           //关闭
           sqlSession.close();
       }
   }

   @Test
   public void getuserById(){
       // 获得sqlsession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       try{
           // 1.执行 getmapper
           UserMapper userDao = sqlSession.getMapper(UserMapper.class);
           User user = userDao.getUserById(1);

           System.out.println(user);


       }catch(Exception e){
           e.printStackTrace();
       }finally{
           //关闭
           sqlSession.close();
       }
   }

   @Test
   public void addUser(){
       // 获得sqlsession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       try{
           // 1.执行 getmapper
           UserMapper userDao = sqlSession.getMapper(UserMapper.class);
           userDao.addUser(new User(6, "kun","123"));

       }catch(Exception e){
           e.printStackTrace();
       }finally{
           //关闭
           sqlSession.close();
       }
   }

   @Test
   public void updateUser(){
       // 获得sqlsession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       try{
           // 1.执行 getmapper
           UserMapper userDao = sqlSession.getMapper(UserMapper.class);
           userDao.updateUser(new User(6, "fang","123"));

       }catch(Exception e){
           e.printStackTrace();
       }finally{
           //关闭
           sqlSession.close();
       }
   }

   @Test
   public void deleteUser(){
       // 获得sqlsession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       try{
           // 1.执行 getmapper
           UserMapper userDao = sqlSession.getMapper(UserMapper.class);
           userDao.deleteUser(6);

       }catch(Exception e){
           e.printStackTrace();
       }finally{
           //关闭
           sqlSession.close();
       }
   }
}

关于@Param()注解

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

十.Lombok

1.在IDEA中安装lombok插件

2.配置

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
</dependencies>
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@Data: 无参构造,get,set,toString,hashCode

4.在实体类上加注解:

package com.hou.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private int id;
    private String name;
    private String password;

}

多对一

  • 多个学生关联一个老师(多对一)

  • 集合(一对多)

  1. 建表
CREATE TABLE `teacher` (
	`id` INT(10) NOT NULL PRIMARY KEY,
	`name` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher (`id`, `name`) VALUES (1, 'hou');

CREATE TABLE `student` (
	`id` INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	`tid` INT(10) DEFAULT NULL,
	PRIMARY KEY (`id`),
	KEY `fktid` (`tid`),
	CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO student (`id`, `name`, `tid`) VALUES (1, 'xiao1', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (2, 'xiao2', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (3, 'xiao3', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (4, 'xiao4', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (5, 'xiao5', 1);

1.新建实体类

package com.hou.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;

    //学生需要关联一个老师
    private Teacher teacher;
}
package com.hou.pojo;

import lombok.Data;

@Data
public class Teacher {
    private int id;
    private String name;
}

2.建立Mapper接口

3.建立Mapper.xml

4.测试是否能够成功

2. 按照查询嵌套处理
StudentMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.hou.dao.StudentMapper">

    <select id="getStudent" resultMap="StudentTeacher">
      select * from student;
    </select>

    <resultMap id="StudentTeacher" type="com.hou.pojo.Student">
        <result property="id" column="id"></result>
        <result property="name" column="name"></result>
        <!--对象使用assiociation-->
        <!--集合用collection-->
        <association property="teacher" column="tid"
                     javaType="com.hou.pojo.Teacher"
                     select="getTeacher"></association>
    </resultMap>

    <select id="getTeacher" resultType="com.hou.pojo.Teacher">
      select * from teacher where id = #{id};
    </select>

</mapper>
  1. 按照结果嵌套处理
select s.id sid,s.name sname,t.name tname
from student s,teacher t where s.tid=t.id;
<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid,s.name sname,t.name tname
    from student s,teacher t where s.tid=t.id;
</select>

<resultMap id="StudentTeacher2" type="com.hou.pojo.Student">
    <result property="id" column="sid"></result>
    <result property="name" column="sname"></result>
    <association property="teacher" javaType="com.hou.pojo.Teacher">
        <result property="name" column="tname"></result>
    </association>

</resultMap>

property 映射到列结果的字段或属性。

column 数据库中的列名,或者是列的别名。

一对多

一个老师拥有多个学生

对于老师而言就是一对多

1.环境搭建
实体类

package com.hou.pojo;

import lombok.Data;
import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;
    private List<Student> studentList;
}
package com.hou.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
  1. 按照结果查询
<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid, s.name sname, t.name tname, t.id tid
    from student s, teacher t
    where s.tid = t.id and t.id = #{id};
</select>

<resultMap id="TeacherStudent" type="com.hou.pojo.Teacher">
    <result property="id" column="tid"></result>
    <result property="name" column="tname"></result>
    <!--集合中的泛型信息,我们用oftype获取-->
    <collection property="studentList" ofType="com.hou.pojo.Student">
        <result property="id" column="sid"></result>
        <result property="name" column="sname"></result>
    </collection>
</resultMap>
  1. 按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from mybatis.teacher where id = #{id}
</select>

<resultMap id="TeacherStudent2" type="com.hou.pojo.Teacher">
    <collection property="studentList" column="id" javaType="ArrayList"
                ofType="com.hou.pojo.Student"
                select="getStudentByTeacherId"></collection>
</resultMap>

<select id="getStudentByTeacherId" resultType="com.hou.pojo.Student">
    select * from mybatis.student where tid = #{id}
</select>

小结

  1. 关联 - association 多对一
  2. 集合 - collection 一对多
  3. javaType & ofType
    JavaType用来指定实体中属性类型
    ofType映射到list中的类型,泛型中的约束类型

注意点:

  • 保证sql可读性,尽量保证通俗易懂
  • 注意字段问题
  • 如果问题不好排查错误,使用日志

动态sql

动态sql:根据不同的条件生成不同的SQL语句
搭建环境

create table `blog`(
	`id` varchar(50) not null comment '博客id',
    `title` varchar(100) not null comment '博客标题',
    `author` varchar(30) not null comment '博客作者',
    `create_time` datetime not null comment '创建时间',
    `views` int(30) not null comment '浏览量'
	)ENGINE=InnoDB DEFAULT CHARSET=utf8

实体类

package com.hou.pojo;

import lombok.Data;

import java.util.Date;

@Data
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

核心配置

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.hou.mapper.BlogMapper">
    <insert id="addBlog" parameterType="Blog">
        insert into mybatis.blog (id, title, author, create_time, views) values
        (#{id}, #{title}, #{author}, #{create_time}, #{views});
    </insert>
</mapper>

新建随机生成ID包

package com.hou.utils;

import org.junit.Test;

import java.util.UUID;

@SuppressWarnings("all")
public class IDUtiles {

    public static String getId(){
        return UUID.randomUUID().toString().replaceAll("-","");
    }

    @Test
    public void  test(){
        System.out.println(getId());
    }

}

测试类:添加数据

import com.hou.mapper.BlogMapper;
import com.hou.pojo.Blog;
import com.hou.utils.IDUtiles;
import com.hou.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;

public class MyTest {

    @Test
    public void addBlog(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);

        Blog blog = new Blog();
        blog.setId(IDUtiles.getId());
        blog.setAuthor("houdongun");
        blog.setCreateTime(new Date());
        blog.setViews(999);
        blog.setTitle("first");

        blogMapper.addBlog(blog);

        blog.setId(IDUtiles.getId());
        blog.setTitle("second");
        blogMapper.addBlog(blog);

        blog.setId(IDUtiles.getId());
        blog.setTitle("third");
        blogMapper.addBlog(blog);

        blog.setId(IDUtiles.getId());
        blog.setTitle("forth");
        blogMapper.addBlog(blog);

        sqlSession.close();
    }
}

if

<select id="queryBlogIF" parameterType="map" resultType="Blog">
    select * from mybatis.blog where 1=1
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != author">
        and author = #{author}
    </if>
</select>

test

@Test
public void queryBlogIF(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();

    //        map.put("title", "second");
    map.put("author", "houdongun");

    List<Blog> list = blogMapper.queryBlogIF(map);

    for (Blog blog : list) {
        System.out.println(blog);
    }

    sqlSession.close();
}

choose、when、otherwise

<select id="queryBlogchoose" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

trim、where、set

<update id="updateBlog" parameterType="map">
    update mybatis.blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author}
        </if>
    </set>
    where id = #{id}
</update>

trim 可以自定义

SQL片段
有些时候我们有一些公共部分

1.使用sql便签抽取公共部分

2.在使用的地方使用include标签

<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 mybatis.blog
    <where>
        <include refid="if-title-author"></include>
    </where>
</select>

注意:

最好基于单表
sql里不要存在where标签

for-each

<!--ids是传的,#{id}是遍历的-->
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <foreach collection="ids" item="id" open="and ("
                 close=")" separator="or">
            id=#{id}
        </foreach>
    </where>
</select>

test

@Test
public void queryBlogForeach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();

    ArrayList<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(3);
    map.put("ids",ids);

    List<Blog> list = blogMapper.queryBlogForeach(map);

    for (Blog blog : list) {
        System.out.println(blog);
    }

    sqlSession.close();
}

12. 缓存(了解)

1. 一级缓存
1.开启日志
2.测试一个session中查询两次相同记录。
缓存失效:

  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  • 查询不同的mapper.xml
  • 手动清除缓存
    一级缓存默认开启,只在一次sqlseesion中有效

2. 二级缓存
开启全局缓存

<setting name="cacheEnabled" value="true"/>

在当前mapper.xml中使用二级缓存

<cache eviction="FIFO"
       flushInterval="60000"
       size="512"
       readOnly="true"/>

test

@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SqlSession sqlSession1 = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.queryUserByid(1);
    System.out.println(user);
    sqlSession.close();

    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
    User user1 = userMapper1.queryUserByid(1);
    System.out.println(user1);
    System.out.println(user==user1);
    sqlSession1.close();
}

只用cache时加序列化

<cache/>

实体类

package com.hou.pojo;

import lombok.Data;
import java.io.Serializable;

@Data
public class User implements Serializable {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
}

小结:

  • 只有开启了二级缓存,在Mapper下有效
  • 所有数据都会先放在一级缓存
  • 只有当回话提交,或者关闭的时候,才会提交到二级缓存

3. 自定义缓存-ehcache

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.0</version>
</dependency>

ehcache.xml

<?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.tmpdir – 默认临时文件路径
     -->
    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:缓存最大数目
      maxElementsOnDisk:硬盘最大缓存个数。
      eternal:对象是否永久有效,一但设置了,timeout将不起作用。
      overflowToDisk:是否保存到磁盘,当系统当机时
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->
    <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"/>

</ehcache>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用:史上最全Java面试宝典,BAT大厂面试必备。整理不易,建议先关注点赞加收藏 序号名称地址1Java基础面试题(91道含答案)(点击查看)2Java并发编程面试题 (123道含答案)(点击查看)3Java异常面试题 (33道含答案)(点击查看)4Java虚拟机(JVM)面试题(51道含答案)(点击查看)5Java集合面试题(52道含答案)(点击查看)6Linux面试题(50道含答案)(点击查看)7Memcache面试题(23道含答案)(点击查看)8Mybatiss面试题 (37道含答案)(点击查看)9MySQL面试题(40道含答案)(点击查看)10Netty面试题(49道含答案)(点击查看)11Nginx面试题(23道含答案)(点击查看)12RabbitMQ面试题(22道含答案)(点击查看)13Redis面试题(70道含答案)(点击查看)14SpringBoot面试题(44道含答案)(点击查看)15SpringCloud面试题(49道含答案)(点击查看)16SpringMVC面试题(29道含答案)(点击查看)17Spring面试题(75道含答案)(点击查看)18TCP、UDP、Socket、Http网络编程面试题(47道含答案)(点击查看)19Tomcat面试题(15道含答案)(点击查看)20Zookeeper面试题(28道含答案)(点击查看)21多线程面试题(60道含答案)(点击查看)22设计模式面试题(14道含答案)(点击查看)23BIO、NIO、AIO、Netty面试题(35道含答案)(点击查看)24Dubbo面试题(47道含答案)(点击查看)25ElasticSearch面试题(31道含答案)(点击查看)26Git常用命令(63条)(点击查看)。 引用:运行Spring Boot应用程序:可以使用spring-boot:run命令在开发阶段启动Spring Boot应用程序。 引用:生成Spring Boot项目文档:可以使用spring-boot:help命令生成Spring Boot项目的文档。11.SpringBoot 打成jar和普通的jar有什么区别? Spring Boot的打包方式主要有两种,一种是打成可执行的jar包,另一种是传统的普通jar包。两者的区别在于可执行的jar包中包含了一个内嵌的Tomcat服务器,可以直接运行,而普通的jar包则需要在外部环境中运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值