Mybatis学习笔记

全网最全老杜Mybatis笔记

ORM(MyBatis属于半自动化ORM框架)

什么是ORM?

像User这样的类,有特殊的称呼:
有的人把它叫做: pojo(普通java类)

有的叫做: bean(豆子)
有的叫做: domain(领域模型) 

环境准备:

考虑到mybatis学习要用到maven

所以来复习一下Maven是怎么配置的!

Maven 

1.先下载Maven

Maven – Welcome to Apache Maven

2.修改配置镜像

 搜索镜像 maven.aliyun.com

把之前的文件内容注释,添加阿里镜像 

3.新建文件夹仓库

4.配置idea

 

-DarchetypeCatalog=internal 

5.重启idea 

第一个mybatis程序

开发我的第一个MyBatis程序


1.resources目录:


放在这个目录当中的,一般都是资源文件,配置文件。
直接放到resources目录下的资源,等同于放到了类的根路径下。


2.开发步骤(前两步在pom.xml里)


第一步:打包方式 jar

<packaging>jar</packaging>


第二步:导入依赖



Maven的远程仓库
https://mvnrepository.com

搜索mybatis,搜索mysql

如下:

<dependencies>
<!-- mysql -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.31</version>
</dependency>


<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>

</dependencies>

第三步:编写mybatis核心配置文件:

mybatis-config.xml
注意:
第一这个文件名不是必须叫做mybatis-config.xml,可以用其他的名字。只是大家都采用这个名字。

第二:这个文件存放的位置也不是固定的,可以随意,但一般情况下,会放到类的根路径下。

怎么配置呢?

我们从mybatis中文网

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="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

其他的代码看不懂,我们应该能看懂(显然是连接数据库的)

来配置一下:

                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>

 第四步:编写XxxxMapper.xml文件

在这个配置文件当中编写SQL语句。

这个文件名也不是固定的,放的位置也不是固定,我们这里给它起个名字,叫做:CarMapper.xml把它暂时放到类的根路径下。

配置也是从mybatis中文网复制:

<?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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

写一个插入语句吧:

<insert id="">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values (null,'1003','丰田',30,'2003-08-09','燃油车')
</insert>

第五步:在mybatis-config.xml文件中指定XxxxMapper.xml文件的路径:


<mapper resource="CarMapper. xml"/>
注意:resource属性会自动从类的根路径下开始查找资源。

而CarMapper. xml刚好在根目录下。

第六步:编写mybatis程序

现在我们正式进入mybatis学习 

先创建软件包

创建第一个java:

package com.powenode.mybatis.test;

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.InputStream;

public class day1 {
    public static void main(String[] args) throws Exception{
        //获取sqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //获取SqlSessionFactory对象
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory build = sqlSessionFactoryBuilder.build(is);
        //获取SqlSession对象
        SqlSession sqlSession = build.openSession();
        //执行sql语句
        int count = sqlSession.insert("insertCar");//执行影响的行数
        System.out.println(count);
        //提交
        sqlSession.commit();

    }
}

成功了!!!!

第一个比较完整的Mybatis程序

package com.powenode.mybatis.test;

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;

public class mybatisComplete {
    public static void main(String[] args) {
        SqlSession sqlSession=null;
        try {
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
            sqlSession = sqlSessionFactory.openSession();
            //执行sql语句
            int count = sqlSession.insert("insertCar");
            System.out.println(count);
            //处理到这没有发现异常,提交事务,终止事务
            sqlSession.commit();
        } catch (Exception e) {
            if (sqlSession!=null){
                sqlSession.rollback();
            }
            e.printStackTrace();
        }finally {
            if (sqlSession != null){
                sqlSession.close();
            }
        }

    }
}

和上面的程序差不多,就是更加完整了。。。

junit复习

新建一个模块进行复习

导入依赖:

    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

 开始操作:

规范:

单元测试方法写多少个(一般是一个业务方法对应一个测试方式
测试方法的规范:public void testXxxx(){}
测试方法的方法名:以test开始。假设测试的方法是sum,这个测试方法名:testSum

@Test注解非常重要,被这个注解标注的方法就是一个单元测试方法。

这俩个里的代码:

package test;

public class mathService {
    public int sum(int a,int b){
        return a+b;
    }
}

测试:

package text;

import org.junit.Assert;
import org.junit.Test;
import test.mathService;

public class mathServiceTest {
    @Test
    public void testSum(){
        mathService ms = new mathService();
        int actual = ms.sum(3, 1);
        int espected = 4;
        Assert.assertEquals(espected,actual);
    }
}

我们单纯的输出信息的话,不便于调试,所以有日志;

Mybatis集成日志框架

我们来实现第三方的日志组件-------------->

集成logback日志框架:

第一步:添加框架支持
  <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.11</version>
            <scope>test</scope>
        </dependency>
第二步:引入logback的xml配置文件

这个配置文件的名字必须叫做: logback.xml或者logback-test.xml,不能是其它的名字。

这个配置文件必须放到类的根路径下。不能是其他位置。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <springProperty scope="context" name="logName" source="logging.file.name" defaultValue="log.log" />
    <!--定义日志文件的存储地址-->
    <property name="LOG_HOME" value="${logName}" />
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" />

    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- 输出到日志文件 -->
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}.%d{yyyy-MM-dd}.%i</FileNamePattern>
            <MaxHistory>30</MaxHistory>
            <MaxFileSize>50MB</MaxFileSize>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 自定义logger -->
    <logger name="com.dispart" level="debug" additivity="false">
        <appender-ref ref="console" />
    </logger>
    <!--sql语句执行输出-->
    <logger name="org.apache.ibatis" level="debug" additivity="false">
        <appender-ref ref="console" />
    </logger>

    <root level="info" additivity="false">
        <appender-ref ref="console" />
    </root>
</configuration>

用junit测试:


 

每一次获取sqlSession对象太过于繁琐,我们可以自己封装一个工具类:

Mybatis工具类SqlSessionUtil的封装

封装类如下:

package mybatis.util;

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;


public class SqlSessionUtil {
//工具类的构造方法一般都是私有化的。
//工具类中所有的方法都是静态的,直接采用类名即可调用。不需要new对象。
// 为了防止new对象,构造方法私有化。
private SqlSessionUtil(){}
private static SqlSessionFactory build;
//类加载时运行
// SqlSessionUtil工具类在进行第一次加载的时候,解析mybatis-config.xml文件。创建SqLSessionFactory对象。
static {
try {
build = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static SqlSession openSession(){
return build.openSession();
}

}

现在用junit去测试一下:

@Test
public void utilTest(){
SqlSession sqlSession = SqlSessionUtil.openSession();
int count = sqlSession.insert("insertCar");
System.out.println(count);
sqlSession.commit();
}

没有问题!

使用Mybatis完成CRUD

C:create

R:retrieve

U:update

D:delete

就是数据库的基本操作,增删改查;

mybatis完成insert,利用pojo类传参;

创建car的pojo类;

package pojo;

public class car {
    //数据库表当中的字段应该和pojo类的属性一一对应。
    // 建议使用包装类,这样可以防止null的问题。
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCarNum() {
        return carNum;
    }

    public void setCarNum(String carNum) {
        this.carNum = carNum;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getGuidePrice() {
        return guidePrice;
    }

    public void setGuidePrice(Double guidePrice) {
        this.guidePrice = guidePrice;
    }

    public String getProduceTime() {
        return produceTime;
    }

    public void setProduceTime(String produceTime) {
        this.produceTime = produceTime;
    }

    public String getCarType() {
        return carType;
    }

    public void setCarType(String carType) {
        this.carType = carType;
    }

    public car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
        this.id = id;
        this.carNum = carNum;
        this.brand = brand;
        this.guidePrice = guidePrice;
        this.produceTime = produceTime;
        this.carType = carType;
    }
}

修改car的xml文件(#{pojo类的元素})

<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values (#{id},#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType});
</insert>

测试:

public void test(){
car car = new car(null, "3333", "比亚迪", 30.00, "2003-09-03", "电车");
SqlSession sqlSession = SqlSessionUtil.openSession();
sqlSession.insert("insertCar",car);
sqlSession.commit();
sqlSession.close();
}

mybatis完成delete

这个就比较简单了,因为只要一个元素,id去删除

我们先在car的xml文件里去加一个删除的操作;

<delete id="deleteById">
delete from t_car where id = #{id};
</delete>

然后进行操作:

public void test_1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
sqlSession.delete("deleteById",7);
sqlSession.commit();
sqlSession.close();
}

mybatis完成update

这个和上面的insert有点相似;

我们先在car的xml文件里去加一个更新的操作;

public void test_2(){
car car = new car(6L, "3333", "比亚迪", 30.00, "2003-09-03", "电车");
SqlSession sqlSession = SqlSessionUtil.openSession();
sqlSession.delete("updateById",car);
sqlSession.commit();
sqlSession.close();
}

mybatis完成select查询

完成一次查询

car的xml文件:

<select id="selectById" resultType="pojo.car">
select id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
from t_car
where id=#{id};
</select>

注:

1.resultType="pojo.car"这个是指定类的类型为car

2.为什么不写 select * from t_car where id = #{id}呢?因为这样可能有些结果是null,表的列名要和pojo类的类名一样才可以查出结果,所以要用别名;

测试代码:

public void test_3(){
SqlSession sqlSession = SqlSessionUtil.openSession();
Object car = sqlSession.selectOne("selectById", 1);
System.out.println(car);
sqlSession.commit();
sqlSession.close();
}

select查询所有;

老样子:

<select id="selectAll" resultType="pojo.car">
select id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
from t_car
</select>

测试:

public void test_4(){
SqlSession sqlSession = SqlSessionUtil.openSession();
List<Object> all = sqlSession.selectList("selectAll");
all.forEach(car-> System.out.println(car));
sqlSession.commit();
sqlSession.close();
}

namespace的作用

命名空间,如果有操作的id有相同的话,前面要加上namespace;

就比如再写一个xml文件,执行select操作,id与之前的xml文件相同的话

核心配置文件

多环境

当要多个数据库使用的时候,我们来配置;

使用:

事务管理器 

事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
    <transactionManager type="MANAGED">
      <property name="closeConnection" value="false"/>
    </transactionManager>

数据源(dataSource)

如:

<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>

有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):

来看pooled:

POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:

  • poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10
  • poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
  • poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
  • poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
  • poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnections 与 poolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
  • poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
  • poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
  • poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。

属性(properties)

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

这时候可以在根目录下创建一个jdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/powernode
jdbc.username=root
jdbc.password=root

然后再在核心配置文件的去引入;

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

然后再获取:用${}

<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>

在web中应用mybatis

先建立一张数据库的表:

插入数据:

创建一个新模块:

添加依赖:

先创建包:com.powernode里

 编辑account类:

package com.powernode.pojo;

public class account {
    private Long id;
    private String actno;
    private Double balance;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getActno() {
        return actno;
    }

    public void setActno(String actno) {
        this.actno = actno;
    }

    public Double getBalance() {
        return balance;
    }

    public void setBalance(Double balance) {
        this.balance = balance;
    }
}

再加一个之前写的工具类:

 再配置根目录:

写前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>银行转账系统</title>
</head>
<body>
<form action="/transfer" method="post">
    转出账号:<input name="from" type="text"><br>
    转入账号:<input name="to" type="text"><br>
    转账金额:<input name="money" type="text">
    <input type="submit" value="提交">
</form>
</body>
</html>

接下来不想写了。。。。。

mybatis事务的控制:

上面的web应用的一部分:

业务层:

package com.powernode.service.imp;

import com.powernode.dao.accountD;
import com.powernode.dao.imp.accountDImp;
import com.powernode.exceptions.noMoneyException;
import com.powernode.exceptions.transferException;
import com.powernode.pojo.account;
import com.powernode.service.accService;

public class accServiceImp implements accService {
private accountD us= new accountDImp();
public void transfer(String from,String to,double money) throws noMoneyException, transferException {
//查询是否钱够用
double balance = us.selectA(from).getBalance();
double balance2 = us.selectA(to).getBalance();

if (balance>=money){
//钱足够的话
double t1 = balance - money;
double t2 = balance2+ money;
//封装pojo类
account ac1 = new account();
ac1.setActno(from);
System.out.println(t1);
ac1.setBalance(t1);

account ac2 = new account();
ac2.setActno(to);
ac2.setBalance(t2);
//更新
int i = us.updateA(ac1);
//在这发生异常的话,会导致钱减少了,但是没转账成功
int i1 = us.updateA(ac2);
if(i+i1!=2){
throw new transferException("转账失败");
}
}
else{
throw new noMoneyException("余额不够,请充值");
}
}
}

我们怎么解决这个问题呢?

应该在这个业务层去创建SqlSession对象,并且提交;

所以要修改一下代码:

数据库控制层把commit等代码删掉;

修改工具类:

public static SqlSession openSession(){
        SqlSession sqlSession = local.get();
        if(sqlSession==null){
            sqlSession=build.openSession();
            //将sqlSession绑定到当前线程上
            local.set(sqlSession);
        }
        return sqlSession;
    }
    public static void Close(SqlSession sqlSession){
        sqlSession.close();
//从当前线程移除sqlSession对象
        local.remove();
    }

业务层: 

public void transfer(String from,String to,double money) throws noMoneyException, transferException {
SqlSession sqlSession = SqlSessionUtil.openSession();
//查询是否钱够用
double balance = us.selectA(from).getBalance();
double balance2 = us.selectA(to).getBalance();

if (balance>=money){
//钱足够的话
double t1 = balance - money;
double t2 = balance2+ money;
//封装pojo类
account ac1 = new account();
ac1.setActno(from);
System.out.println(t1);
ac1.setBalance(t1);

account ac2 = new account();
ac2.setActno(to);
ac2.setBalance(t2);
//更新
int i = us.updateA(ac1);

int i1 = us.updateA(ac2);
if(i+i1!=2){
throw new transferException("转账失败");
}
}
else{
throw new noMoneyException("余额不够,请充值");
}
sqlSession.commit();
SqlSessionUtil.closeS(sqlSession);

}

javassist动态生成类 

pom.xml文件里写好依赖

<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.0-GA</version>
</dependency>

</dependencies>

来写:

package javassist;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;

public class javassistTest {
    @Test
    public void test() throws Exception {
        //获取类池,这个是生成class类的
        ClassPool pool = ClassPool.getDefault();
        //制造类,需要知道类的名称
        CtClass ctClass = pool.makeClass("com.powernode.dao.imp.accountDImp");
        //制造方法
        String methodCode = "public void update(){System.out.print(222);}";
        CtMethod method = CtMethod.make(methodCode, ctClass);
        //将方法添加到类中
        ctClass.addMethod(method);
        //在内存中生成class
        ctClass.toClass();

        //类加载到jvm中,返回类的字节码文件
        Class<?> aClass = Class.forName("com.powernode.dao.imp.accountDImp");
        //创建对象
        Object o = aClass.newInstance();
        //获取类中的方法
        Method update = aClass.getDeclaredMethod("update");
        //调用方法
        update.invoke(o);

    }
}

。。。。。。这个太繁琐,我们直接跳过 

MyBatis的getMapper()方法

动态生成接口的实现类

注意:namespace不能随便写了,要写接口的路径

还有操作的id要和接口的方法名一样

使用

private accountD us = SqlSessionUtil.openSession().getMapper(accountD.class);

面向接口的方式进行CRUD 

import mapper.carD;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import pojo.car;
import util.SqlSessionUtil;

import java.util.List;

public class test {
    @Test
    public void update(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        carD mapper = sqlSession.getMapper(carD.class);
        car car = new car(6L, "4444", "比亚迪", 30.00, "2003-09-03", "电车");
        mapper.updateById(car);
        sqlSession.commit();
    }
    @Test
    public void delete(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        carD mapper = sqlSession.getMapper(carD.class);
        mapper.deleteById(6L);
        sqlSession.commit();
    }
    @Test
    public void insert(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        carD mapper = sqlSession.getMapper(carD.class);
        car car = new car(6L, "4444", "比亚迪", 30.00, "2003-09-03", "电车");
        mapper.insertCar(car);
        sqlSession.commit();
    }
    @Test
    public void select(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        carD mapper = sqlSession.getMapper(carD.class);
        car car = mapper.selectById(6L);
        System.out.println(car);
        sqlSession.commit();
    }
    @Test
    public void selectA(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        carD mapper = sqlSession.getMapper(carD.class);
        List<car> cars = mapper.selectAll();
        cars.forEach(car -> System.out.println(car));
        sqlSession.commit();
    }
}

#{}和${}的区别究竟是什么呢?

  如果需要SQL语句的关键字放到SQL语句中,只能使用${},因为#{}是以值的形式放到SQL语句当中的。

#{}先编译再放值进去

${}先进行字符串拼接再编译,有sql注入的风险

mybatis小技巧

-批量删除

carMapper.xml

<delete id="plDelete">
delete from t_car where id in (${id});
</delete>

接口里:

public void plDelete(String id); 

测试:

@Test
public void plDeleteTest(){
SqlSession sqlSession = SqlSessionUtil.openSession();
carD mapper = sqlSession.getMapper(carD.class);
mapper.plDelete("5,6");
sqlSession.commit();
}

--模糊查询 

有两种方法可以用,第一个方法用${}

别名机制 

mapper小技巧 

使用自动生成的主键值

用map集合去插入数据 

三剑客

@Test
public void insertByMapTest(){
SqlSession sqlSession = SqlSessionUtil.openSession();
carD mapper = sqlSession.getMapper(carD.class);
HashMap<String, Object> map = new HashMap<>();
map.put("id",16L);
map.put("carNum","5555");
map.put("brand","小米");
map.put("guidePrice",30);
map.put("produceTime","1999-08-07");
map.put("carType","油车");
mapper.insertByMap(map);
sqlSession.commit();
sqlSession.close();

}

<insert id="insertByMap">
insert into t_car values (#{id},#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType});
</insert>

public void insertByMap(Map map); 

mybatis之多参数 

我们之前写的都是单个参数,现在如果我们想完成一个select操作用2个参数去搜索,该怎么去实现呢?

mybatis会为我们自动封装一个map集合,我们用该方法去取值:

我们来试试:

<select id="selectByTwo" resultType="pojo.car">
select id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
from t_car
where brand=#{param1} and car_type = #{param2};
</select>

public void selectByTwoTest(){
SqlSession sqlSession = SqlSessionUtil.openSession();
carD mapper = sqlSession.getMapper(carD.class);
List<car> cars = mapper.selectByTwo("比亚迪","电车");
cars.forEach(car -> System.out.println(car));
sqlSession.commit();
sqlSession.close();
}

public List<car> selectByTwo(String b,String t); 

param注解

public List<car> selectByTwo(@Param("brand") String b, @Param("car_type") String t); 

Mybatis查询专题之返回map集合

返回一个map

<select id="selectToMap" resultType="map">
select id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
from t_car
where id=#{id};
</select>

 public Map<String, Objects> selectToMap(Long id);

@Test
public void selectToMapTest(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Map<String, Objects> stringObjectsMap = mapper.selectToMap(11L);
System.out.println(stringObjectsMap);
sqlSession.commit();
sqlSession.close();
}

返回多个map

唯一要注意的点,不是list是map 

返回一个大map 

大map的key是id

@MapKey("id")
public Map<Long,Map<String,Objects>> selectToBigMap();

Mybatis结果映射 

之前写select语句的时候,要求取别名,不然会出现null的现象。

很是不爽,我们可以设置一个结果映射。如下:

●驼峰自动映射

要符合:

开启: 

查询返回数字 

<select id="countAll" resultType="long">
select count(*) from t_car;
</select>

public Long countAll(); 

动态sql

 if标签

<select id="ifOfSelect" resultType="Car">
select id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
from t_car
where 1=1
<if test="price != null and price != ''">
and guide_price >= #{price}
</if>
<if test="brand != null and brand != ''">
and brand like "%"#{brand}"%"
</if>
<if test="type != null and type != ''">
and car_type = #{type}
</if>
</select>

public List<Car> ifOfSelect(@Param("brand") String b,@Param("price") Double p,@Param("type") String t); 

where标签 

不需要写1=1了,我们直接把上面写的if放到where里就行,and(or)写在前面的话,会自己消除.

trim标签

<trim prefix="where" suffixOverrides="and|or">
<if test="price != null and price != ''">
guide_price >= #{price} and
</if>
<if test="brand != null and brand != ''">
brand like "%"#{brand}"%" and
</if>
<if test="type != null and type != ''">
car_type = #{type}
</if>
</trim>

set标签

 

choose标签 

必然有一个条件会执行,全为null,最后一个也会执行; 

foreach批量删除 

<delete id="deleteOfForeach">
delete from t_car where id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>

public void deleteOfForeach(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Long[] its={14L,15L,16L};
mapper.deleteOfForeach(its);
sqlSession.commit();
sqlSession.close();
}

 public void deleteOfForeach(@Param("ids") Long[] ids);

foreach批量添加 

<insert id="insertMore">
insert into t_car values
<foreach collection="cars" item="car" separator=",">
(#{car.id},#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
</foreach>
</insert>

public void insertMore(@Param("cars") List<Car> cars);

@Test
public void insertMore(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = new ArrayList<>();
Car car1 = new Car(null, "4444", "比亚迪", 30.00, "2003-09-03", "电车");
Car car2 = new Car(null, "4444", "比亚迪", 30.00, "2003-09-03", "电车");
Car car3 = new Car(null, "4444", "比亚迪", 30.00, "2003-09-03", "电车");
cars.add(car1);
cars.add(car2);
cars.add(car3);
System.out.println(car1.getId());
mapper.insertMore(cars);
sqlSession.commit();
sqlSession.close();
}

多对一映射

mysql基础

多表联查--01---LEFT JOIN 实现多表联查_多表left join-CSDN博客

准备2张表

t_stu

t_class

按之前准备环境:

2张表2个mapper和pojo

2个xml文件 

第一种方法,用sql的查询语句 

<?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="ljy.mapper.StudentMapper">
    <resultMap id="StudentMap" type="Student">
        <id property="sid" column="sid"/>
        <result property="sName" column="name"/>
        <result property="c.cid" column="cid"/>
        <result property="c.classN" column="classN"/>
    </resultMap>
    <select id="OneSelect" resultMap="StudentMap">
          select s.sid,s.name,c.cid,c.classN
          from t_stu s left join t_class c on s.cid=c.cid
          where s.sid = #{sid}
    </select>
</mapper>

第二种方式:

和第一种方式差不多

<resultMap id="selectByIdAssociation" type="Student">
        <id property="sid" column="sid"/>
        <result property="sName" column="name"/>
        <association property="c" javaType="CLASS">
            <id property="cid" column="cid"/>
            <result property="classN" column="classN"/>
        </association>
    </resultMap>
    <select id="selectByAssociation" resultMap="selectByIdAssociation">
        select s.sid,s.name,c.cid,c.classN
        from t_stu s left join t_class c on s.cid=c.cid
        where s.sid = #{sid}
    </select>

第三种方式:分布查询

先查学生的班级cid,再根据cid查班级

<resultMap id="selectByIdMoreStep" type="Student">
<id property="sid" column="sid"/>
<result property="sName" column="name"/>
<association property="c" select="ljy.mapper.ClassMapper.selectByIdStepTwo" column="cid"/>
</resultMap>

<select id="selectByidStepOne" resultMap="selectByIdMoreStep">
select sid,name,cid from t_stu where sid = #{sid}
</select>

注意:<association property="c" select="ljy.mapper.ClassMapper.selectByIdStepTwo" column="cid"/>

property是Student里的CLASS里的c

select 是第二次搜索的select方法的id

column是传的参数

第二次搜索

<select id="selectByIdStepTwo" resultType="CLASS">
select cid,classN from t_class where cid =#{cid};
</select>

延迟加载

延迟加载(lazy load) (也称为懒加载,也叫延迟实例化,延迟初始化等)主要表达的思想就是:把对象的创建延迟到使用的时候创建,而不是对象实例化的时候创建。延迟加载机制是为了避免一些无谓的性能开销而提出来的,这种方式避免了性能的浪费。所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。

如果我们不想要某个延迟加载的话------》

 一对多映射:

第一种方法

以t_class为主表

在class类里面要给出关联,多加一个list集合来装t_stu表的数据

以及stus的get和set方法

核心代码:

<resultMap id="Classtwo" type="CLASS">
<id property="cid" column="cid"/>
<result property="classN" column="classN"/>
<collection property="stus" ofType="Student">
<id property="sid" column="sid"/>
<result property="sName" column="name"/>
</collection>
</resultMap>
<select id="selectByCid" resultMap="Classtwo">
select c.cid,c.classN,s.sid,s.name from t_class c left join t_stu s on c.cid=s.cid where c.cid = #{cid};
</select>

要把student里面之前写的关联t_class表的东西删了;

第二种方法:

和之前的多对一一样,分步查询;

MyBatis的缓存


缓存: cache
缓存的作用:通过减少IO的方式,来提高程序的执行效率。
mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO,另一方面不再执行繁琐的查找算法。效率大大提升。
 

一级缓存

不用自己开启,mybatis自动开启

同一个sqlsession是有缓存的

那一级缓存什么时候失效呢?

二级缓存

什么时候二级缓存失效呢?

Mybatis逆向工程 

让我们体验下怎么自动生成相关文件

第一步:环境准备

打包方式jar 

 第二步:在pom中添加逆向工程的插件

<?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>com.powernode</groupId>
    <artifactId>mybatis-012-generator</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    
<!--    逆向工程所引用的插件(需要引入的插件)-->

    <!--定制构建过程-->
    <build>
        <!--可配置多个插件-->
        <plugins>
            <!--其中的⼀个插件:mybatis逆向工程插件-->
            <plugin>
                <!--插件的GAV坐标-->
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.1</version>
                <!--允许覆盖-->
                <configuration>
                    <overwrite>true</overwrite>
                </configuration>
                <!--插件的依赖-->
                <dependencies>
                    <!--mysql驱动依赖-->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.30</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project>

在类的根目录下创建generatorConfig.xml,一定只能是这个名字 

内容为:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
    targetRuntime有两个值:
    MyBatis3Simple:生成的是基础版,只有基本的增删改查。
    MyBatis3:⽣成的是增强版,除了基本的增删改查之外还有复杂的增删改查。
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!--防⽌生成重复代码-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>

        <commentGenerator>
            <!--是否去掉生成日期-->
            <property name="suppressDate" value="true"/>
            <!--是否去除注释-->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--连接数据库信息,这里需要修改成自己数据库信息-->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis_powernode"
                        userId="root"
                        password="123456789">
        </jdbcConnection>
        <!-- 生成pojo包名和位置 -->
        <javaModelGenerator targetPackage="com.powernode.mybatis.pojo" targetProject="src/main/java">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
            <!--是否去除字段名的前后空白-->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成SQL映射文件的包名和位置 -->
        <sqlMapGenerator targetPackage="com.powernode.mybatis.mapper" targetProject="src/main/resources">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成Mapper接口的包名和位置 -->
        <javaClientGenerator
                type="xmlMapper"
                targetPackage="com.powernode.mybatis.mapper"
                targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 表名和对应的实体类名-->
        <table tableName="t_car" domainObjectName="Car"/>
    </context>
</generatorConfiguration>

最后一步:

点击后即可生成;

接下来进行测试:

我们要和之前一样,引入必须的依赖;

<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.31</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>

工具类也自己引入:

接下来:

把核心配置文件复制过来:

接下来进行测试:

@Test
public void testAuto(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectAll();
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}

增强版: 

自动生成更加全面的数据库操作文件

我们重新做下准备工作,按之前的方式,就改下targetRuntime的值。

接下来,来看看怎么使用:

@Test
public void test(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
//查全部
List<Car> cars = mapper.selectByExample(null);
cars.forEach(car -> System.out.println(car));

//按条件查
CarExample carExample = new CarExample();
carExample.createCriteria().andBrandEqualTo("比亚迪");
List<Car> cars1 = mapper.selectByExample(carExample);
cars1.forEach(car -> System.out.println(car));
sqlSession.close();
}

分页管理

普通写法: 

核心代码:

<select id="paging" resultType="Car">
select * from t_car limit #{startIndex},#{pageSize}
</select>

List<Car> paging(@Param("startIndex") int startIndex,@Param("pageSize")int pageSize); 

@Test
public void pagingTest(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
int page = 2;
int pageSize = 3;
int stratIndex=(page-1)*pageSize;
List<Car> paging = mapper.paging(stratIndex, pageSize);
paging.forEach(p-> System.out.println(p));
sqlSession.close();
}

pageHelper 分页插件

1、POM依赖

Mybatis的配置就不多提了。PageHelper的依赖如下。

            <!-- pagehelper 分页插件 -->
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>1.4.0</version>
            </dependency>

2、Mybatis对PageHelper的配置

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

3.使用

  <select id="autoPaging" resultType="Car">
    select * from t_car
  </select>
List<Car> autoPaging();
@Test
    public void autoPaging(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        PageHelper.startPage(2,3);
        List<Car> cars = mapper.autoPaging();
        cars.forEach(car -> System.out.println(car));
        sqlSession.close();
    }

拿到分页的数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘家奕_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值