MyBatis笔记

Mybatis

Mybatis介绍

什么是Mybatis?

mybatis是支持普通SQL查询存储过程高级映射的优秀持久层框架

Mybatis优点

  • 几乎消除了JDBC代码和参数的手动设置
  • 消除结果集的检索
  • 使用XML或注解用于配置和原始映射,将接口和POJOs(实体类)映射成数据库中的记录。

Mybatis特点

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql

Mybatis功能构架

我们把Mybatis的功能架构分为三层:

1.API接口层 2.数据处理层 3.基础支撑层

**API接口:**提供给外部使用的API接口,开发人员使用本地API接口操作数据库。接口层一收到调用请求,就会调用数据处理层进行具体的数据处理。

**数据处理层:**负责具体的SQL查询,SQL解析、SQL执行以及执行结果集映射的处理。主要目的是根据调用进行一次操作数据库

**基础支撑层:**负责最基础的支撑,包括 连接管理、事务管理、配置加载、缓冲加载。这些都是公用的的基础组件。

框架解析

框架架构讲解:

mybatis结构

(1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。

(2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。

(3)SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。

(4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。

获取Mybatis

  • maven
  • GitHub

持久层

持久化

  • 将程序的数据在持久状态和瞬时状态转化的过程。
  • 内存的特点:断电即失

第一个Mybatis程序

搭建环境

1.搭建数据库
 CREATE DATABASS mybatis;

创建表

USE mybatis
go
CREATE TABLE Users(
    id int not null PRIMARY KEY,
    name varchar default NULL,
    pwd varchar default NULL
)

插入值

insert Users(id,name,pwd) 
values (1,'张三','123456')
insert Users(id,name,pwd) 
values (2,'李四','123456')
insert Users(id,name,pwd) 
values (3,'王五','123456')

另外一种值插入方法

insert into Users 
select 1,'张三','123456'
union 
2.创建项目

导入依赖

sqlServer驱动

<!--sqlServer驱动-->
<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>8.2.2.jre8</version>
</dependency>

mybatis

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

junit

<!--junit-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

创建Module 作为子模块

编写代码

编写Mybatis核心配置文件
<?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.microsoft.sqlserver.jdbc.SQLServerDriver"/>
                <property name="url" value="jdbc:sqlserver://localhost:1433;database=mybatis;useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
                <property name="username" value="sa"/>
                <property name="password" value="1582183834"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/Dao/UsersMapper.xml"/>
    </mappers>
</configuration>
编写工具类

编写工具类 加载使用

public class UsersUtils {
        private static SqlSessionFactory sqlSessionFactory;
    static{
          //获取sqlSessionFactory对象
        try {
            String resource ="mybatis-config.xml";
            InputStream resourceAsStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory =new SqlSessionFactoryBuilder().build(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
         //获取SqlSession实例
       //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
//        SqlSession sqlSession = sqlSessionFactory.openSession();
//        return sqlSession;
    }

}
编写实体类
public class Users implements Serializable {

    private  int id;
    private String name;
    private String pwd;

    public Users() {
    }

    public Users(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;
    }

    @Override
    public String toString() {
        return "Users{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
编写Dao接口 层
interface UsersDao {
    List<Users> getUsersDaoList();
}
编写Dao接口层实现代码的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">
<mapper namespace="com.Dao.UsersDao">
    <select id="getUsersDaoList" resultType="com.pojo.Users">
        select * from Users
    </select>

</mapper>

namespace=“com.Dao.UsersDao”

全限命名法,namespace 表示和某一个类或接口 相匹配

id=“getUsersDaoList”

Select 中的ID表示查询的方法

resultType=“com.pojo.Users”

返回单个的类型,必须表示返回类型所对应的实体类。

测试

测试注意

一般在Text下创建和代码相对应的目录进行测试。

在这里插入图片描述

编写测试代码
public class Text {
    @Test
    public void text(){
        //加载resources资源
            //获取SqlSession对象
        SqlSession sqlSession = UsersUtils.getSqlSession();
            //执行SQL
        UsersDao mapper = sqlSession.getMapper(UsersDao.class);
        List<Users> usersDao = mapper.getUsersDaoList();

        for (Users users : usersDao) {
            System.out.println(users);
        }
        //关闭资源
        sqlSession.close();
    }
}
测试果

在这里插入图片描述

可能会出现的错误

org.apache.ibatis.binding.BindingException: Type interface com.Dao.UsersDao is not known to the MapperRegistry.

错误原因

在核心配置文件中没有没有将UsersDao的xml文件配置注册

解决
   <mappers>
        <mapper resource="com/Dao/UsersMapper.xml"/>
    </mappers>

将UsersDao的xml文件配置到Mybatis核心配置文件当中

IOException: Could not find resource com/Dao/UsersMapper.xml

错误原因

1.没有编写UsersMapper.xml配置文件。

2.因为在Maven项目中,约定大于配置,所以需要手动将Java中的xml打包带出

解决

1.编写UsersMapper.xml文件

2.在Pom文件下加上Build

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

项目代码结构

在这里插入图片描述

CURD

查询

UsersDao接口

//通过id查询用户
Users getUsersById(int id);

映射文件

<select id="getUsersById" resultType="com.pojo.Users" parameterType="int">
    select * from Users where id=#{id}
</select>

测试结果

@Test
public void Text01(){
    SqlSession sqlSession = UsersUtils.getSqlSession();
    UsersDao mapper = sqlSession.getMapper(UsersDao.class);

    Users usersById = mapper.getUsersById(1);

    System.out.println(usersById);

    sqlSession.close();
}

增加

UsersDao接口

//增加用户
int InsertUser(Users users);

映射文件

<insert id="InsertUser" parameterType="com.pojo.Users">
    insert Users(id,name,pwd) values(#{id},#{name},#{pwd})
</insert>

测试

//增加用户
@Test
public void Text02(){
    SqlSession sqlSession = UsersUtils.getSqlSession();
    UsersDao mapper = sqlSession.getMapper(UsersDao.class);
    int s = mapper.InsertUser(new Users(4, "五百", "123456"));
    if (s>0){
        System.out.println("增加用户成功");
    }
   //增删改需要提交事务,否则无法更改
    sqlSession.commit();

    sqlSession.close();
}

修改

UsersDao接口

//更改用户数据
int UpdataUser(Users users);

映射文件

<update id="UpdataUser" parameterType="com.pojo.Users">
    update Users set name=#{name},pwd=#{pwd}  where id=#{id};
</update>

测试

//修改用户  将四号用户的名字改为六百
@Test
public void text03(){
    SqlSession sqlSession = UsersUtils.getSqlSession();
    UsersDao mapper = sqlSession.getMapper(UsersDao.class);
    int liu = mapper.UpdataUser(new Users(4, "六百", "123456"));
    if (liu>0){
        System.out.println("修改用户成功");
    }
    //提交事务
    sqlSession.commit();


    sqlSession.close();
}

删除

UsersDao接口

//删除用户数据
int DelectUser(int id);

映射文件

<delete id="DelectUser" parameterType="int">
    delete from Users where id=#{id};
</delete>

测试

@Test
public void text04(){
    SqlSession sqlSession = UsersUtils.getSqlSession();
    UsersDao mapper = sqlSession.getMapper(UsersDao.class);
    int i = mapper.DelectUser(4);
    if (i>0){
        System.out.println("删除用户成功");
    }
    sqlSession.commit();
    sqlSession.close();
}

完整代码

UsersDao接口

public interface UsersDao {
    //获取列表
    List<Users> getUsersDaoList();
    //通过id查询用户
    Users getUsersById(int id);
    //增加用户
    int InsertUser(Users users);
    //更改用户数据
    int UpdataUser(Users users);
    //删除用户数据
    int DelectUser(int id);
}

映射文件

<?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.Dao.UsersDao">
    <select id="getUsersDaoList" resultType="com.pojo.Users">
        select * from Users
    </select>

    <select id="getUsersById" resultType="com.pojo.Users" parameterType="int">
        select * from Users where id=#{id}
    </select>


    <insert id="InsertUser" parameterType="com.pojo.Users">
        insert Users(id,name,pwd) values(#{id},#{name},#{pwd})
    </insert>

    <update id="UpdataUser" parameterType="com.pojo.Users">
        update Users set name=#{name},pwd=#{pwd}  where id=#{id};
    </update>

    <delete id="DelectUser" parameterType="int">
        delete from Users where id=#{id};
    </delete>
</mapper>

XML配置

首先声明xml中各个配置设置的位置是固定不变的,否则会出现异常

在这里插入图片描述

必须遵循下面的顺序进行设置。

(properties–settings–typeAliases–typeHandlers–objectFactory–objectWrapperFactory–reflectorFactory–plugins–environments–databaseIdProvider–mappers)"

属性(properties)

目前我们学过的属性文件db.properties

在xml文件当中,为了实现我们可以动态修改xml文件,可以在外部设置属性文件引用到mybatis-config.xml文件当中。

属性配置有两种插入方法

1.内部引入

<properties >
    <property name="username" value="sa"/>
    <property name="password" value="1582183834"/>
</properties>

2.外部引入

2.1 首先编写一个properties属性文件。

driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:sqlserver://localhost:1433;database=mybatis;useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=sa
password=1582183834

然后在mybatis-config.xml文件当中

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

环境中属性的更改

<dataSource type="POOLED">
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
</dataSource>

通过${}以实现动态获取properties属性文件当中的属性

若两部分都有部署,首先会执行内部的xml,再执行外部的属性资源,但是内部的某些属性会被外部属性覆盖!

类型别名(typeAliases)

类型别名相当于对动态SQL中的返回类型或者参数类型的优化

例如在查询表单的SQL中的返回类型resultType的返回类型是一个对象

<select id="getUsersDaoList" resultType="com.pojo.Users">
    select * from Users
</select>

这样些写较为麻烦,所以为这个类型设置一个别名

<typeAliases>
    <typeAlias type="com.pojo.Users" alias="Users"/>
</typeAliases>

这样设置类型为Users类的别名就变为Users

<select id="getUsersDaoList" resultType="Users">
    select * from Users
</select>

package类型别名

package 顾名思义是包 package类型别名,即是扫描包

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

扫描包

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

例如 在pojo包下有一个名为User的类,那么扫描后的返回类型就为user

注解别名

和上侧相同,当包下的类有注解时,注解为Alias(“”)

则此时的返回类型就为注解内容,并且和类名无关

例如 在pojo包下有一个名为User的类,注解为Alias(“hello”),那么扫描后的返回类型为hello,并不为user

换一种说法,也就是在扫描包别名是,注解的优先级大于类名别名优先级

映射器配置

映射器

映射器配置共有3中配置方法

1.resource

<mappers>
    <mapper resource="com/Dao/UsersMapper.xml"/>
</mappers>

配置这种资源,每一层需要斜杠间隔(/)

2.class

<mappers>
    <mapper class="com.Dao.UsersMapper"/>
</mappers>

使用映射器中的class映射必须遵守以下规则,否则就会报错

  • 接口和它的Mapper配置文件名称保持一致
  • 接口和它的Mapper配置文件需要在同一个包下

3.package扫描方法

<mappers>
    <package name="com.Dao"/>
</mappers>

使用映射器中的package方法也必须遵循以下规则

  • 接口和它的Mapper配置文件名称保持一致
  • 接口和它的Mapper配置文件需要在同一个包下

另外还有一种url路径反射,因为路径问题,所以很难寻找(不建议使用)。

<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

mybatis官方url定位介绍

ResultMap

问题

当pojo中的字段与数据库中的字段不同时,则可能会导致项目某些功能运行失败

在这里插入图片描述

因为字段名不一致,运行结果导致结果查询失败

在这里插入图片描述

解决方法

方法一

(起别名)

select * from Users

相当于

select id,name,pwd from Users

为此,我们必须为pwd起一个别名

select id,name,pwd as password from Users

然后就可以查询到password这个字段对应在数据库pwd中的值了

方法二;

(更改前)使用ResultMap集合

<select id="getUsersDaoList" resultType="users">
    select id,name, pwd as password from Users
</select>

(更改后)其中resultType更换为resultMap

<select id="getUsersDaoList" resultMap="usersResultMap">
    select id,name, pwd from Users
</select>

然后追加一个属性

<resultMap id="" type="">
    <result column="" property=""/>
</resultMap>

此处标签属性介绍

id - 相当于绑定标识 -在这里绑定到 resultMap=“usersResultMap” -即id=“usersResultMap”

type-相当于返回类型–返回类型为实体类中的类—type =“Users”

column–列表,数据库中的字段–column=“pwd”

property–属性,java类中字段名–property=“password”

<resultMap id="usersResultMap" type="users">
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>

当然,在我们这个实例当中,字段id和name和数据库中的字段并没有区别,所以我们可以适当进行删减

<resultMap id="usersResultMap" type="users">
    <result column="pwd" property="password"/>
</resultMap>

这样就体现到了resultMap的一个优点

是否使用resultMap

当连表查询等复杂查询时,建议使用resultMap 进行项目创建

当仅仅是简单查询时,不建议使用resultMap

为了保证项目的简洁,建议在创建实体类时,最后将数据库和实体类中的字段名一一对应。

日志

日志工厂

日志简而言之是提供操作记录,有时便于我们进行排错

日志工厂在设置中进行添加,即

在这里插入图片描述

key–> logImpl

value—>

  • SLF4J
  • LOG4J (常用)
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING (常用,标准)
  • NO_LOGGING

重要使用日志工厂时,必须保证大小写,数量一致,空格多少也会导致错误。

STDOUT_LOGGING

STDOUT_LOGGING

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

观察控制台输出结果

前部分一些处理(暂且不看)

在这里插入图片描述

在这里插入图片描述

总体来说便于理解如何实现SQL查询

LOG4J

什么是LOG4J
  • Log4j是Apache的一个开发源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的实践记录器、UNIX Syslog守护进程等;
  • 我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
  • 可以通过一个配置文件进行灵活的配置
导入LOG4J包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

配置LOG4J配置
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/caiji.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

将大括号改为英文下的

运行后可能出现的问题

在这里插入图片描述

日志目录下的log存在打不开的现象

出现的原因可能有

  • 在Mybatis核心配置文件当中<typeAlices 别名采用的是包扫描的方法
  • 在Mybatis核心配置文件当中<mapper 扫描资源时使用的是包扫描方法

解决

  • 将包扫描改为其他方式查找资源
LOG4J日志化打印格式

Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:

%m输出代码中指定的消息;

%M输出打印该条日志的方法名;

%p输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL;

%r输出自应用启动到输出该log信息耗费的毫秒数;

%c输出所属的类目,通常就是所在类的全名;

%t输出产生该日志事件的线程名;

%n输出一个回车换行符,Windows平台为"rn”,Unix平台为"n”;

%d输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy-MM-ddHH:mm:ss,SSS},输出类似:2002-10-1822:10:28,921;

%l输出日志事件的发生位置,及在代码中的行数。

LOG4J简单应用

首先需要一个Logger对象,获取当前类的信息,并通过这个对象来进行操作日志

static  Logger logger = Logger.getLogger(Text.class);    //因为日志好多都需要使用,所以要提升作用域

然后进行一个简单的测试

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

@Test
public void TestLOG4J(){
    logger.info("INFO:进入方法");
    logger.debug("DEBUG:进入方法");
    logger.error("ERROR:进入方法");
}

其中,logger.info logger.debug logger.error 相当于java中的System.out.println()

测试结果

在这里插入图片描述

log日志

在这里插入图片描述

输出了方法

其中,优先级 Error >Info>debug

OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL 以此递减

Limit分页

首先,如果使用的是SQLServer数据库,那么他的分页方法有四种,并不是Limit关键字进行分页

limit关键字是mySql数据库进行分页操作时的关键字。

在这里使用SQLServer数据库进行分页查询

使用map为参数查询

编写分页查询接口

//分页
List<Users> getUsersLimit(Map<String,Integer> map);

采用传递Map接口来传递参数更快捷简单

编写接口配置文件

<select id="getUsersLimit" parameterType="map" resultMap="usersResultMap" >
    select top ${pageSize} * from Users where id not in(select top ${pageIndex} id from Users ORDER BY id)
</select>

其中usersResultMap绑定在resultMap当中,用于上一次解决字段名不相同问题

${pageSize} 以及 ${pageIndex} 为自定义名字,用于传递参数,在测试类当中我们将以此为Key值进行传递参数。

需要注意的是:

在编写SQL语句时,一般在数据库具有字段可变参格式 例如,id=#{id}

自行构造参数传递时,例如分页查询,其传递参数仅仅为#{pageSize}

当SQL语句当中top 等关键字出现时,传递的参数格式就需要 ${pageSize}

原因是top关键字后占位符不能使用#{}来进行占位 但是有可能会有注入问题出现

编写Test测试

@Test
public void TestLimit(){
    SqlSession sqlSession = UsersUtils.getSqlSession();
    UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
    HashMap<String,Integer > map = new HashMap<String,Integer >();
    map.put("pageSize",2);
    map.put("pageIndex",1);
    List<Users> us = mapper.getUsersLimit(map);
    for (Users u : us) {
        System.out.println(u);
    }
    sqlSession.close();
}

RowBounds分页查询(了解)

RowBounds查询属于面向对象查询(官方不建议使用)

编写Mapper接口

List<Users> getRowBounds();

编写接口配置文件即SQL

<select id="getRowBounds" resultMap="usersResultMap">
    select * from Users
</select>

测试类

简单查询分页,没有调用UsersMapper接口中的方法,不需要获取其反射对象

@Test
public void TestRowBounds(){
    SqlSession sqlSession = UsersUtils.getSqlSession();

    RowBounds rowBounds = new RowBounds(1,2);
				//另一种获取Mapper接口的方法					//权限命名 
    List<Users> usersList = sqlSession.selectList("com.Dao.UsersMapper.getRowBounds", null, rowBounds);

    for (Users users : usersList) {
        System.out.println(users);
    }
    sqlSession.close();
}

注解开发

一个简单的注解开发案例

编写接口

//注解开发
@Select("select * from Users")
List<Users> getUsersList();

将mybatis核心配置文件的映射部分改为Class映射

<mappers>
    <mapper class="com.Dao.UsersMapper"></mapper>
</mappers>

编写测试类

@Test
public void TestCom(){
    SqlSession sqlSession = UsersUtils.getSqlSession();
    UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
    List<Users> List = mapper.getUsersList();
    for (Users users : List) {
        System.out.println(users);
    }
    sqlSession.close();
}

CURD

编写接口

//注解开发
@Select("select * from Users")
List<Users> getUsersList();
//增
@Insert("Insert Users (id,name,pwd) values(#{id},#{name},#{password})")
int insertUsers(Users users);
//改
@Update("update Users set name=#{name},pwd=#{password} where id=#{id}")
int updateUsers(Users users);
//删
@Delete("delete from Users where id=#{id}")
int delectUsers(@Param("id") int id);

@Param参数注解,后面参数名称

测试类

省略

lombok

多对一的处理

搭建复杂SQL查询环境

创建Student表

create table Student(
   id  int  not NULL primary key,
   name  varchar(20)  Null,
   tid int null
)

创建Teacher表

create table Teacher(
 id int not NULL primary key,
    name varchar(20)  null
)

创建外键

alter table Student
add constraint  FK_Student_tid foreign key(tid) references Teacher (id)

association 多对一 多个学生面对同一个老师

collection 集合 一对多 一个老师拥有多个学生

实体类
public class Student {
    private int id;
    private String name;
    private Teacher teacher;
    }
public class Teacher {
    private int id;
    private String name;
    }

按照查询嵌套处理

<select id="getStudentList" resultMap="TeacherStudent">
       select * from Student
</select>
<select id="getTeacher" resultType="Teacher">
       select * from Teacher where id=#{tid}
</select>
<resultMap id="TeacherStudent" type="Student">
       <result property="id" column="id"></result>
       <result property="name" column="name"></result>
       <association property="teacher"  column="tid" javaType="Teacher" select="getTeacher"></association>
</resultMap>

按照结果嵌套处理

<select id="getStudentInformation" resultMap="TeacherStudent2">
       select s.id  sid, s.name sname, t.name tname from Student s,Teacher t where s.tid=t.id
</select>
<resultMap id="TeacherStudent2" type="Student">
       <result property="id" column="sid"/>
       <result property="name" column="sname"/>
       <association property="teacher" column="tname" javaType="Teacher">
              <result property="name" column="tname"/>
       </association>
</resultMap>

接口类

public interface StudentMapper {

    //获取学生别表
//    @Select("select * from Student")
    List<Student> getStudentList();
    //获取学生信息
    List<Student> getStudentInformation();
}

一对多处理

一个老师拥有多个学生

collection 集合

实体类

public class Student {
    private int id;
    private String name;
    }
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;
    }

按照查询嵌套处理

<select id="getTeacherList" resultMap="TeacherStudent">
    select * from Teacher where id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
    <collection property="students" column="id" javaType="ArrayList" ofType="Student"  select="getStudent"/>
</resultMap>
<select id="getStudent" resultType="Student">
    select * from Student where tid =#{id}
</select>

按照结果嵌套处理

<select id="getList" resultMap="List">
    select s.id sid, s.name sname ,t.id tid ,t.name tname from Student s,Teacher t where s.tid=t.id and s.tid=#{id}
</select>
<resultMap id="List" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <collection property="students" column="tid" ofType="Student" >
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
    </collection>
</resultMap>

接口类

public interface TeacherMapper {
    //获取老师列表

    List<Teacher> getTeacherList(@Param("id")int id);
    //查询全部
    List<Teacher> getList(@Param("id")int id);

}

动态SQL环境搭建

什么是动态SQL

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

创建表

在这里插入图片描述

利用mybatis 添加数据

pojo实体类

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

数据库中的字段名与实体类中的横杠不统一

createTime----create_time

解决方法

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

在mybatis-config.xml核心配置文件当中设置

开启驼峰转换

BlogMapper

    //添加Blog用户
   int addBlogList(Blog blog);

BlogMapper.xml

<insert id="addBlogList" parameterType="Blog" >
    insert Blog(id,title,author,create_time,views)values(#{id},#{title},#{author},#{createTime},#{views})
</insert>

测试类

//添加用户
@Test
public void addBlogList(){
    SqlSession sqlSession = UserUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Blog blog = new Blog();

    blog.setId(IDUtils.getUUid());
    blog.setTitle("JAVA的入门");
    blog.setAuthor("咸鱼");
    blog.setCreateTime(new Date());
    blog.setViews(9999);
    mapper.addBlogList(blog);

    blog.setId(IDUtils.getUUid());
    blog.setTitle("JAVA的开始");
    blog.setAuthor("咸鱼");
    blog.setCreateTime(new Date());
    blog.setViews(8080);
    mapper.addBlogList(blog);

    blog.setId(IDUtils.getUUid());
    blog.setTitle("JAVA的进阶");
    blog.setAuthor("咸鱼");
    blog.setCreateTime(new Date());
    blog.setViews(6666);
    mapper.addBlogList(blog);

    blog.setId(IDUtils.getUUid());
    blog.setTitle("JAVA的精通");
    blog.setAuthor("咸鱼");
    blog.setCreateTime(new Date());
    blog.setViews(9999);
    mapper.addBlogList(blog);


    sqlSession.close();
}

动态SQL—if

当我们想要做一个类似于查找的功能时,例如通过title和author进行模糊查找

我们可以选择只填写title 或者只填写author

如果仅仅采用编写多个方法来应对不同的需求时,那么这些代码将有很多重复,不简洁

select * from User where title=? and author=?

select * from User where title=?

select * from User where author=?

这样写一个功能 使用3个sql进行多次查询?

这样也太麻烦了

为此

我们将采用动态sql中的if查询

同样是上侧的案例

接口方法:(采用map作为参数进行传值,通过put进行动态添加key,value)

//动态SQLif
List<Blog> getList(Map map);

mapper.xml

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

首先,先书写一个用于查询全部数据的SQL语句,然后在后添加一个Where 1=1 ,添加where 1=1 的目的就是在没有任何条件下的查询语句 ,其作用和 select * from Blog 作用相等(但是在项目书写代码中,where 1=1并不符合规范,这里使用仅仅是为了学习if,接下来会有解决这个问题的知识。)

然后在使用if语句进行判断,当有title这个值存在时,就把他拼接进去。同理 author也是如此。

这样就使用一个sql语句就解决带有N多种条件的查询啦!

动态SQL—where

where

解决where 1=1 的问题

//动态SQLif2 where标签
List<Blog> getList2(Map map);
<select id="getList2" parameterType="map" resultType="Blog">
    select * from Blog
    <where>
        <if test="title!=null">
            and title =#{title}
        </if>
        <if test="author!=null" >
            and author=#{author}
        </if>
    </where>
</select>

添加where标签,可以在if满足的条件下,自动添加where标签。并且自动检测是否在第一项,自动省略第一个条件的and标签。

另外,有时候where自动省略and 或者or 标签失败。

所以,解决此问题的方法自定义设定

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

prefix------前缀

prefixOverrides------前缀覆盖

set

//动态SQL update  set标签
int updateList(Map map);
<update id="updateList" >
    update Blog
    <set>
        <if test="title!=null">title=#{title},</if>
        <if test="author!=null">author=#{author}</if>
    </set>
    where id=#{id}
</update>

自动将后面的,进行覆盖或者显现

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

choose、when、otherwise

//choose选择
 List<Blog> getListChoose(Map map);
<select id="getListChoose" parameterType="map" resultType="Blog">
    select * from  Blog 
    <where>
        <choose>
         <when test="title!=null"> and title=#{title}</when>
         <when test="author!=null">and author=#{author}</when>
       <otherwise>
           and views=#{views}
       </otherwise>
        </choose>

    </where>
    
</select>

choose选择器,相当于java中的while 当第一中符合时,其余的都不会有效

当有一种符合时,其他都会无效。

SQL片段

//sql片段。实现sql复用
List<Blog> getList3(Map map);
<select id="getList3" 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">
        and title =#{title}
    </if>
    <if test="author!=null" >
        and author=#{author}
    </if>
</sql>

定义sql以实现sql 的复用

最好不要将where等标签放入sql语句当中,以提供sql语句的多次复用

foreach(*

//sqlforeach查询
List<Blog> getList4(Map map);
<select id="getList4" parameterType="map" resultType="Blog">
    select * from Blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
         id=#{id}
        </foreach>
    </where>

</select>

测试

//sqlforeach
@Test
public void getIfListTest4(){
    SqlSession sqlSession = UserUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    ArrayList ids = new ArrayList();
    ids.add("1");
    ids.add("2");
    map.put("ids",ids);
    List<Blog> list2 = mapper.getList4(map);
    for (Blog blog : list2) {
        System.out.println(blog);
    }
    sqlSession.close();
}

在这里插入图片描述

在这里分隔符需要使用or 其他可能会报错

动态SQL,就是在拼接SQL,保证SQL的正确性,按照SQL格式

缓存

在Mybatis当中,分为一级缓存和二级缓存

一级缓存

一级缓存和SQLsession同级别

在创建session和关闭session之间有效。

缓存可以缓存所有的select语句,每当出现update、insert、delect出现时,缓存将会失效,将会被刷新

一级缓存是默认缓存

二级缓存

在这里插入图片描述

虽然在设置当中默认开启了二级缓存的总开关,但是为了保证代码的可读性,建议在xml核心配置文件当中设置

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

在Mapper里添加下面的标签开启二级缓存

<cache/>

Mybatis缓存原理

在这里插入图片描述

(首次)开启sqlsession查询数据库,然后存入一级缓存,当SQLsession关闭后,一级缓存将会存入该Mapper中的二级缓存当中。

(再次)查询过程

r">

and title =#{title} and author=#{author} ```

定义sql以实现sql 的复用

最好不要将where等标签放入sql语句当中,以提供sql语句的多次复用

foreach(*

//sqlforeach查询
List<Blog> getList4(Map map);
<select id="getList4" parameterType="map" resultType="Blog">
    select * from Blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
         id=#{id}
        </foreach>
    </where>

</select>

测试

//sqlforeach
@Test
public void getIfListTest4(){
    SqlSession sqlSession = UserUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    ArrayList ids = new ArrayList();
    ids.add("1");
    ids.add("2");
    map.put("ids",ids);
    List<Blog> list2 = mapper.getList4(map);
    for (Blog blog : list2) {
        System.out.println(blog);
    }
    sqlSession.close();
}

[外链图片转存中…(img-vgNIQlbm-1703315948656)]

在这里分隔符需要使用or 其他可能会报错

动态SQL,就是在拼接SQL,保证SQL的正确性,按照SQL格式

缓存

在Mybatis当中,分为一级缓存和二级缓存

一级缓存

一级缓存和SQLsession同级别

在创建session和关闭session之间有效。

缓存可以缓存所有的select语句,每当出现update、insert、delect出现时,缓存将会失效,将会被刷新

一级缓存是默认缓存

二级缓存

[外链图片转存中…(img-TXo9UTXP-1703315948657)]

虽然在设置当中默认开启了二级缓存的总开关,但是为了保证代码的可读性,建议在xml核心配置文件当中设置

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

在Mapper里添加下面的标签开启二级缓存

<cache/>

Mybatis缓存原理

(首次)开启sqlsession查询数据库,然后存入一级缓存,当SQLsession关闭后,一级缓存将会存入该Mapper中的二级缓存当中。

(再次)查询过程

先从二级缓存中查询是否有此查询的缓存,若没有,然后在一次缓存当中查询是否有此缓存,如果都没有,那么连接数据库,进行查询。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/266435.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt/QML编程学习之心得:在QML中调用fileDialog(十六)

Qt中有一些内置的对话框dialog,比如 在QWidget工程中使用比较容易,比如 #include <QFileDialog>fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)")); 那么在QM…

oracle即时客户端(Instant Client)安装与配置

之前的文章记录了oracle客户端和服务端的下载与安装&#xff0c;内容参见&#xff1a; 在Windows中安装Oracle_windows安装oracle 如果不想安装oracle客户端&#xff08;或者是电脑因为某些原因无法安装oracle客户端&#xff09;&#xff0c;还想能够连接oracle远程服务&#…

智能优化算法应用:基于原子轨道搜索算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于原子轨道搜索算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于原子轨道搜索算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.原子轨道搜索算法4.实验参数设定…

智能优化算法应用:基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.跳蛛算法4.实验参数设定5.算法结果6.参考文献7.MA…

贪吃蛇(十)贪吃蛇吃食物

上节讲到限制蛇身回头&#xff0c;本节要实现吃食物功能 实现思路 在存储上食物方面可以复用蛇的结构体。初始化食物的时候&#xff0c;我们设置食物的坐标&#xff0c;每次调用这个函数的时候&#xff0c;坐标发生一些规律的变化。另外我们需要扫描食物的函数&#xff0c;这…

科研学习|论文解读——面向电商内容安全风险管控的协同过滤推荐算法研究

【论文完整内容详见知网链接】&#xff1a; 面向电商内容安全风险管控的协同过滤推荐算法研究 - 中国知网 (cnki.net) 面向电商内容安全风险管控的协同过滤推荐算法研究* 摘 要&#xff1a;[目的/意义]随着电商平台商家入驻要求降低以及商品上线审核流程简化&#xff0c;内容安…

一起学量化之macd指标

macd指标 1. macd指标定义 MACD的组成要素MACD称为异同移动平均线&#xff0c;是从双指数移动平均线发展而来的。MACD由一根快线、一根慢线、一根0轴线和无数根红绿柱状线组成。 如下图所示&#xff0c;粉色的是快线&#xff0c;也称DIFF线&#xff1b;蓝色的是慢线&#xf…

线程池构造方法的认识

线程池中构造方法的认识 文章目录 线程池中构造方法的认识corePoolSize (核心线程数)maximumPoolSize&#xff08;最大线程数&#xff09;keepAliveTime(非核心线程的空闲超时时间)TimeUnitworkQueuethreadFactoryRejectedExecutionHandler拒绝策略 标准库中提供了一个ThreadPo…

C语言 enum类型

enum,枚举,是 C 语言中的一种基本数据类型&#xff0c;用于定义一组具有离散值的常量&#xff0c;它可以让数据更简洁&#xff0c;更易读。 语法&#xff1a; enum 枚举名 {枚举元素1,枚举元素2,……}; 直接上例子 #include<stdio.h> enum DAY { MON1, TUE, WED, TH…

华为鸿蒙应用--封装数据持久化工具:首选项Preferences(鸿蒙工具)-ArkTs

一、使用方法&#xff1a; 0、初始化实例&#xff1a;一般在EntryAbility.ts的onWindowStageCreate中初始化&#xff1b;&#xff08;可忽略&#xff09; 1、将数据写入Preferences实例 function() {let arrayNum: number[] [1, 2, 3];let arrayStr: string[] ["5&quo…

2023美团机器人研究院学术年会成功举办

2023年12月19日&#xff0c;深圳市美团机器人研究院学术年会在清华大学深圳国际研究生院成功落下帷幕。会议回顾了研究院成立一年来的进展和成果&#xff0c;并邀请了各界专家共同讨论机器人技术的未来发展趋势。此外&#xff0c;年会期间还举办了首届低空经济智能飞行管理挑战…

Web前端复习

一、随堂练习 1.小题 margin vanish&#xff1a;border和inline-block都可以形成bfc二维数组转置&#xff1a;res[i] [];函数的不同声明定义&#xff1a; 有变量名字的函数&#xff0c;即便后面声明了同样的&#xff0c;以函数表达式为主&#xff1b;定义&#xff0c;运行。再…

VS Code实现“Ctr+save”保存代码自动格式化

一、下载Prettier - Code formatter插件 点击安装即可 二、配置 【1】打开文件——首选项——设置 或者左下角齿轮打开设置 【2】搜索设置框输入editor default formatter&#xff08;意思是默认格式化设置&#xff09;&#xff0c;接着下拉选中刚下好的插件名称Prettier - C…

网络爬虫之多任务数据采集(多线程、多进程、协程)

进程&#xff1a;是操作系统中资源分配的基本单位 线程&#xff1a;使用进程分配的资源处理具体任务 一个进程中可以有多个线程&#xff1a;进程相当于一个公司&#xff0c;线程就是公司里面的员工。 一 多线程 多线程都是关于功能的并发执行。而异步编程是关于函数之间的非…

N-136基于springboot,vue在线聊天系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;TypeScriptVue3.0ElementUI-Plus 服务端技术&#xff1a;springboo…

【常见的语法糖(详解)】

&#x1f7e9; 说几个常见的语法糖 &#x1f7e2;关于语法糖的典型解析&#x1f7e2;如何解语法糖&#xff1f;&#x1f7e2;糖块一、switch 支持 String 与枚举&#x1f4d9;糖块二、泛型&#x1f4dd;糖块三、自动装箱与拆箱&#x1f341;糖块四、方法变长参数&#x1f5a5;️…

十.MySQL数据类型精讲(一)

MySQL数据类型精讲 1.MySQL中的数据类型2.整数类型2.1类型介绍2.2可选属性2.2.1 M 2.2UNSIGNED2.3ZEROFILL2.3使用场景2.4如何选择 3.浮点类型3.1类型介绍3.2数据精度说明3.3精度误差说明 4.定点数类型4.2开发中经验 5.位类型&#xff1a;BIT 1.MySQL中的数据类型 类型类型举例…

小白入门之安装MAVEN

重生之我在大四学JAVA 第六章 安装MAVEN 打开IDEA&#xff0c;配置MAVEN 打开Setting 找到上面设置的settings.xml文件地址 至此MAVEN也就安装成功了 附赠一个maven清理脚本&#xff0c;如果发现你的电脑maven下载不了jar&#xff0c;依赖爆红&#xff0c;可以试下下面bat脚…

limma:单通道数据和RNA-seq数据差异性分析标准方法

前言 单通道数据极为流行&#xff0c;三大公司&#xff1a;Affymetrix、Illumina和Agilent的微阵列&#xff08;microarray&#xff09;技术产生的很多都是单通道数据。现在的主力的高通量测序机所产生的也是单通道数据&#xff0c;所以只要是被voom标准化&#xff08;包括了l…

【操作系统】学习操作系统知识

文章目录 前言测量系统调用和上下文切换的成本purify 和 valgrindxx3 的执行过程 前言 ref&#xff1a;http://ges.cs.wisc.edu/~remzi/OSTEP/Chinese 零散的记录知识&#xff0c;看《操作系统引论》 测量系统调用和上下文切换的成本 上下文切换需要多长时间&#xff1f;甚…