Mybatis快速入门1

1.MyBatis快速入门

1.1数据库环境搭建

CREATE TABLE cars  
(  
  id           BIGINT AUTO_INCREMENT PRIMARY KEY,  
  car_num      VARCHAR(255),  
  brand        VARCHAR(255),  
  guide_price  DECIMAL(10, 2),  
  produce_time CHAR(10),  
  car_type     VARCHAR(255)  
);  
  
insert into cars (id, car_num, brand, guide_price, produce_time, car_type)  
values (1, '京A00001', '宝马', 100000.00, '2010-01-01', '商务车'),  
       (2, '京A00002', '奔驰', 200000.00, '2010-01-01', '商务车');

image.png

1.2创建空项目,引入依赖。

新建模块mybatis-001-introduction

1.2.1步骤1:打包方式:jar

不需要war,因为mybatis封装的是jdbc。

<groupId>com.powernode</groupId>
<artifactId>mybatis-001-introduction</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

1.2.2步骤2:引入依赖

<!--mybatis核心依赖-->  
<dependency>  
    <groupId>org.mybatis</groupId>  
    <artifactId>mybatis</artifactId>  
    <version>3.5.10</version>  
</dependency>  
<!--mysql驱动依赖-->  
<dependency>  
    <groupId>mysql</groupId>  
    <artifactId>mysql-connector-java</artifactId>  
    <version>8.0.30</version>  
</dependency>

1.2.3步骤3:配置文件

在resources根目录下新建mybatis-config.xml配置文件(可以参考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.mysql.cj.jdbc.Driver"/>  
                <property name="url" value="jdbc:mysql://localhost:3306/rainsoul"/>  
                <property name="username" value="root"/>  
                <property name="password" value="root"/>  
            </dataSource>  
        </environment>  
    </environments>  
  
    <mappers>  
        <!--sql映射文件创建好之后,需要将该文件路径配置到这里-->  
        <mapper resource="CarMapper.xml"/>  
    </mappers>  
</configuration>
  1. 注意1:mybatis核心配置文件的文件名不一定是mybatis-config.xml,可以是其它名字。
  2. 注意2:mybatis核心配置文件存放的位置也可以随意。这里选择放在resources根下,相当于放到了类的根路径下。

1.2.4步骤4:新建CarMapper.xml配置文件

在resources根目录下新建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="car">  
    <insert id="insertCar">  
        insert into cars            
        (id, car_num, brand, guide_price, produce_time, car_type)        
	        values 
        (null, '102', '丰田mirai', 40.30, '2014-10-05', '氢能源')  
    </insert>  
</mapper>
  1. 注意1:sql语句最后结尾可以不写“;”
  2. 注意2:CarMapper.xml文件的名字不是固定的。可以使用其它名字。
  3. 注意3:CarMapper.xml文件的位置也是随意的。这里选择放在resources根下,相当于放到了类的根路径下。
  4. 注意4:将CarMapper.xml文件路径配置到mybatis-config.xml:
<mapper resource="CarMapper.xml"/>

1.2.5 步骤5:编写代码

新建包com.rainsoul.mybatis.test。新建类MyBatisIntroductionTest

public class MyBatisIntroductionTest {
    public static void main(String[] args) {
        // 1. 创建 SqlSessionFactoryBuilder 对象,用于构建 SqlSessionFactory
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        
        // 2. 创建 SqlSessionFactory 对象,用于创建 SqlSession
        // 使用当前线程的类加载器加载 mybatis-config.xml 配置文件
        InputStream is = Thread.currentThread()
	        .getContextClassLoader()
	        .getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        
        // 3. 创建 SqlSession 对象,用于执行 SQL 语句
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        // 4. 执行 SQL
        // insertCar 是在 mybatis-config.xml 中配置的一个 SQL 语句的 ID
        int count = sqlSession.insert("insertCar"); // 这个"insertCar"必须是sql的id
        System.out.println("插入几条数据:" + count);
        
        // 5. 提交事务(mybatis 默认采用的事务管理器是 JDBC,默认是不提交的,需要手动提交)
        sqlSession.commit();
        
        // 6. 关闭资源(只关闭是不会提交的)
        sqlSession.close();
    }
}

在这段代码中,我们做了以下几件事情:

  1. 创建了 SqlSessionFactoryBuilder 对象,用于构建 SqlSessionFactory
  2. 通过类加载器加载了 MyBatis 的配置文件 mybatis-config.xml,并创建了 SqlSessionFactory 对象。
  3. 使用 SqlSessionFactory 创建了 SqlSession 对象,用于执行 SQL 语句。
  4. 执行了一条插入数据的 SQL 语句,这里的 SQL 语句是在 mybatis-config.xml 中配置的,其 ID 为 insertCar
  5. 提交了事务,因为 MyBatis 默认采用的事务管理器是 JDBC,所以需要手动提交。
  6. 关闭了 SqlSession 资源,释放连接。

1.2.6MyBatis核心对象

在 MyBatis 中,SqlSessionFactorySqlSessionFactoryBuilderSqlSession 之间存在以下关系:

  1. SqlSessionFactoryBuilder

    • SqlSessionFactoryBuilder 是用于创建 SqlSessionFactory 实例的建造者类。
    • 它负责从配置信息中构建出 SqlSessionFactory 实例。
  2. SqlSessionFactory

    • SqlSessionFactory 是 MyBatis 的核心接口之一,用于创建 SqlSession 实例。
    • 它是线程安全的,通常在应用程序启动时创建一次,之后被重复使用。
    • SqlSessionFactory 通过读取 MyBatis 的配置文件(如 XML 配置文件)来创建 SqlSession 对象。
    • SqlSessionFactory 对象一旦创建就应该保持全局唯一,通常被设计为单例模式。
  3. SqlSession

    • SqlSession 是 MyBatis 中执行 SQL 操作的主要接口之一,相当于对数据库会话的封装。
    • 它提供了执行 SQL、获取映射器(Mapper)、管理事务等功能。
    • SqlSession 对象是非线程安全的,因此每个线程都应该拥有自己的 SqlSession 实例,并且在使用完毕后应该及时关闭。
    • SqlSession 实例的生命周期应该尽量缩短,即尽早创建、尽快关闭,以释放数据库连接和其他资源。

关系总结:

  • SqlSessionFactoryBuilder 用于创建 SqlSessionFactory 实例,通常在应用程序启动时执行一次。
  • SqlSessionFactory 用于创建 SqlSession 实例,通常是应用程序中的一个全局唯一对象。
  • SqlSession 用于执行具体的 SQL 操作,每次操作完成后应该关闭,不建议共享或长时间持有。

这三者之间的关系是:SqlSessionFactoryBuilder 用于创建 SqlSessionFactorySqlSessionFactory 用于创建 SqlSession

1.2.7运行结果

image.png

1.3关于MyBatis核心配置文件的名字和路径详解

核心配置文件的名字是随意的,因为以下的代码:

// 文件名是出现在程序中的,文件名如果修改了,对应这里的java程序也改一下就行了。

InputStream is = Thread.currentThread()
	.getContextClassLoader()
	.getResourceAsStream("mybatis-config.xml");

mybatis核心配置文件的名字是随意的,存放路径也是随意的。 虽然mybatis核心配置文件的名字不是固定的,但通常该文件的名字叫做:mybatis-config.xml 。虽然mybatis核心配置文件的路径不是固定的,但通常该文件会存放到类路径当中,这样让项目的移植更加健壮。

1.4第一个较为完整的写法

在test包下新建MyBatisCompleteCodeTest

public class MyBatisCompleteCodeTest {  
    public static void main(String[] args) {  
        SqlSession sqlSession = null;  
        try {  
            // 创建SqlSessionFactoryBuilder对象  
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();  
            // 根据配置文件创建SqlSessionFactory对象  
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder  
                    .build(Resources.getResourceAsStream("mybatis-config.xml"));  
            // 通过SqlSessionFactory对象打开一个SqlSession会话  
            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 {  
            // 会话结束,关闭SqlSession  
            if (sqlSession != null) {  
                sqlSession.close();  
            }  
        }  
    }  
}

1.5引入Junit

1.5.1Junit介绍

JUnit 是一个用于编写和运行单元测试的 Java 框架。单元测试是针对软件中的最小可测试单元(通常是方法)进行测试的过程。JUnit 提供了一组注解和断言方法,可以帮助开发者编写和运行测试用例,并且可以方便地进行测试结果的断言和验证。

以下是如何使用 JUnit 进行单元测试的基本步骤:

  1. 添加 JUnit 依赖
    首先需要将 JUnit 框架添加到项目的依赖中。可以通过 Maven、Gradle 或手动下载 JUnit JAR 文件来添加依赖。

  2. 编写测试类
    创建一个测试类,并使用 @Test 注解标记测试方法。测试方法应该是公共的、无返回值的,并且不应该接受任何参数。

    import org.junit.Test;
    import static org.junit.Assert.*;
    
    public class MyTest {
        @Test
        public void testAddition() {
            assertEquals(4, 2 + 2);
        }
    }
    
  3. 运行测试
    可以使用 IDE 或者构建工具来运行测试。大多数 IDE 都集成了对 JUnit 的支持,可以直接右键运行测试类或者测试方法。另外,也可以使用 Maven 或 Gradle 等构建工具来运行测试。

  4. 查看测试结果
    测试运行完成后,会显示测试结果。如果所有测试通过,则会显示“OK”,否则会显示失败的测试用例及其失败原因。

JUnit 还提供了丰富的断言方法,如 assertEquals()assertTrue()assertFalse() 等,用于进行测试结果的断言。通过这些断言方法,可以验证代码的预期行为是否符合预期,从而确保代码的质量和可靠性。

1.5.2引入依赖

<!-- junit依赖 -->  
<dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>4.13.2</version>  
</dependency>

1.5.3编写单元测试类

@Test  
public void testInsertCar() {  
    SqlSession sqlSession = null;  
    try {  
        // 1.创建SqlSessionFactoryBuilder对象  
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();  
        // 2.创建SqlSessionFactory对象  
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder  
                .build(Resources.getResourceAsStream("mybatis-config.xml"));  
        // 3.创建SqlSession对象  
        sqlSession = sqlSessionFactory.openSession();  
        // 4.执行SQL  
        int count = sqlSession.insert("insertCar");  
        System.out.println("更新了几条记录:" + count);  
        // 5.提交  
        sqlSession.commit();  
    } catch (Exception e) {  
        // 回滚  
        if (sqlSession != null) {  
            sqlSession.rollback();  
        }  
        e.printStackTrace();  
    } finally {  
        // 6.关闭  
        if (sqlSession != null) {  
            sqlSession.close();  
        }  
    }  
}

1.6引入日志框架logback

引入日志框架的目的是为了看清楚mybatis执行的具体sql。启用标准日志组件,只需要在mybatis-config.xml文件中添加以下配置:【可参考mybatis手册】

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

标准日志也可以用,但是配置不够灵活,可以集成其他的日志组件,例如:log4j,logback等。
logback是目前日志框架中性能较好的,较流行的,所以我们选它。

1.6.1引入依赖

<dependency>  
    <groupId>ch.qos.logback</groupId>  
    <artifactId>logback-classic</artifactId>  
    <version>1.2.11</version>  
    <scope>test</scope>  
</dependency>

1.6.2logback配置文件

引入logback相关配置文件(文件名叫做logback.xml或logback-test.xml,放到类路径当中)

<?xml version="1.0" encoding="UTF-8"?>  
  
<configuration debug="false">  
    <!-- 控制台输出 -->  
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">  
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>  
        </encoder>  
    </appender>  
    <!-- 按照每天生成日志文件 -->  
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--日志文件输出的文件名-->  
            <FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>  
            <!--日志文件保留天数-->  
            <MaxHistory>30</MaxHistory>  
        </rollingPolicy>  
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">  
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>  
        </encoder>  
        <!--日志文件最大的大小-->  
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">  
            <MaxFileSize>100MB</MaxFileSize>  
        </triggeringPolicy>  
    </appender>  
  
    <!--mybatis log configure-->  
    <logger name="com.apache.ibatis" level="TRACE"/>  
    <logger name="java.sql.Connection" level="DEBUG"/>  
    <logger name="java.sql.Statement" level="DEBUG"/>  
    <logger name="java.sql.PreparedStatement" level="DEBUG"/>  
  
    <!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->  
    <root level="DEBUG">  
        <appender-ref ref="STDOUT"/>  
        <appender-ref ref="FILE"/>  
    </root>  
  
</configuration>

测试效果:
image.png

1.7MyBatis工具类SqlSessionUtil的封装

每一次获取SqlSession对象代码太繁琐,封装一个工具类。新建与test同级的包util。新建类SqlSessionUtil

public class SqlSessionUtil {

    // 私有构造函数,防止实例化该工具类
    private SqlSessionUtil() {
    }

    // 静态成员变量,用于保存全局唯一的 SqlSessionFactory 实例
    private static SqlSessionFactory sqlSessionFactory;

    // 静态代码块,在类加载时执行,用于初始化 SqlSessionFactory
    static {
        try {
            // 创建 SqlSessionFactoryBuilder 对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 通过类加载器加载 MyBatis 配置文件,构建 SqlSessionFactory 实例
            sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (Exception e) {
            // 异常处理,打印异常信息
            e.printStackTrace();
        }
    }
    
    // 静态方法,用于获取 SqlSession 实例
    public static SqlSession openSession() {
        // 调用 SqlSessionFactory 的 openSession 方法获取 SqlSession 实例
        // 参数 true 表示开启自动提交事务
        return sqlSessionFactory.openSession(true);
    }
}

该工具类的作用是提供静态方法 openSession(),用于获取 MyBatis 中的 SqlSession 实例,以便进行数据库操作。在静态代码块中,通过 SqlSessionFactoryBuilder 构建器加载 MyBatis 的配置文件,并创建 SqlSessionFactory 实例。在 openSession() 方法中,通过 SqlSessionFactory 实例的 openSession(true) 方法获取 SqlSession 实例,并设置自动提交事务。

2.使用Mybatis完成CRUD

2.1准备工作

创建module(Maven的普通Java模块):mybatis-002-crud,
pom.xml打包方式jar

mybatis-002-crud/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── rainsoul/
│   │   │           └── mybatis/
│   │   │               ├── CarMapper.java
│   │   │               └── utils/
│   │   │                   └── SqlSessionUtil.java
│   │   ├── resources/
│   │   │   ├── mybatis-config.xml
│   │   │   ├── CarMapper.xml
│   │   │   └── logback.xml
│   └── test/
│       └── java/
│           └── com/
│               └── powernode/
│                   └── mybatis/
│                       └── CarMapperTest.java
└── pom.xml

对于 pom.xml 文件,您可以添加以下依赖项:

<!--mybatis核心依赖-->  
<dependency>  
    <groupId>org.mybatis</groupId>  
    <artifactId>mybatis</artifactId>  
    <version>3.5.10</version>  
</dependency>  
<!--mysql驱动依赖-->  
<dependency>  
    <groupId>mysql</groupId>  
    <artifactId>mysql-connector-java</artifactId>  
    <version>8.0.30</version>  
</dependency>  
<!-- junit依赖 -->  
<dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>4.13.2</version>  
    <scope>test</scope>  
</dependency>  
  
<dependency>  
    <groupId>ch.qos.logback</groupId>  
    <artifactId>logback-classic</artifactId>  
    <version>1.2.11</version>  
    <scope>test</scope>  
</dependency>

2.2insert

分析以下SQL映射文件中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">
<!--namespace先随便写-->
<mapper namespace="car">
	<insert id="insertCar">
		insert into t_car(car_num,brand,guide_price,produce_time,car_type) 
			values
		('103', '奔驰E300L', 50.3, '2022-01-01', '燃油车')
	</insert>
</mapper>

存在的问题是:SQL语句中的值不应该写死,值应该是用户提供的。之前的JDBC代码是这样写的:

String sql = "insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(?,?,?,?,?)";

// 给 ? 传值。那么MyBatis中应该怎么传值呢?

ps.setString(1,"103");
ps.setString(2,"奔驰E300L");
ps.setDouble(3,50.3);
ps.setString(4,"2022-01-01");
ps.setString(5,"燃油车");

在MyBatis中可以这样做:
在Java程序中,将数据放到Map集合中 。在sql语句中使用 #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符。

Java程序:

package com.rainsoul.mybatis.test;  
  
import com.rainsoul.mybatis.pojo.Car;  
import com.rainsoul.mybatis.utils.SqlSessionUtil;  
import org.apache.ibatis.session.SqlSession;  
import org.junit.Test;  
  
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
  
public class CarMapperTest {  
    @Test  
    public void testInsertCar() {  
        // 准备数据

		Map<String, Object> map = new HashMap<>();
		map.put("k1", "103");
		map.put("k2", "奔驰E300L");
		map.put("k3", 50.3);
		map.put("k4", "2020-10-01");
		map.put("k5", "燃油车");
		// 获取SqlSession对象
		SqlSession sqlSession = SqlSessionUtil.openSession();

		// 执行SQL语句(使用map集合给sql语句传递数据)
		int count = sqlSession.insert("insertCar", map);
		System.out.println("插入了几条记录:" + count);
    }  
}

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">
<!--namespace先随便写-->
<mapper namespace="car">
	<insert id="insertCar">
		insert into t_car(car_num,brand,guide_price,produce_time,car_type) 
			values
		(#{k1},#{k2},#{k3},#{k4},#{k5})
		</insert>
</mapper>

#{} 的里面必须填写map集合的key,不能随便写。运行测试程序,查看数据库。插入成功。如果#{}里写的是map集合中不存在的key会有什么问题?将k1改为kk,在此运行,通过测试,看到程序并没有报错。正常执行。不过 #{kk} 的写法导致无法获取到map集合中的数据,最终导致数据库表car_num插入了NULL。 在以上sql语句中,可以看到#{k1} #{k2} #{k3} #{k4} #{k5}的可读性太差,为了增强可读性,我们可以将Java程序做如下修改:

Map<String, Object> map = new HashMap<>();  
// 让key的可读性增强  
map.put("carNum", "103");  
map.put("brand", "奔驰E300L");  
map.put("guidePrice", 50.3);  
map.put("produceTime", "2020-10-01");  
map.put("carType", "燃油车");

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="car">
<insert id="insertCar">
	insert into t_car(car_num,brand,guide_price,produce_time,car_type) 
		values
	(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>
</mapper>

使用Map集合可以传参,那使用pojo(简单普通的java对象)可以完成传参吗?测试一下:

  1. 定义一个Car类:
public class Car {  
    private Long id;  
    private String carNum;  
    private String brand;  
    private Double guidePrice;  
    private String produceTime;  
    private String carType;  
  
    @Override  
    public String toString() {  
        return "Car{" +  
                "id=" + id +  
                ", carNum='" + carNum + '\'' +  
                ", brand='" + brand + '\'' +  
                ", guidePrice=" + guidePrice +  
                ", produceTime='" + produceTime + '\'' +  
                ", carType='" + carType + '\'' +  
                '}';  
    }  
  
    public Car() {  
    }  
  
    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;  
    }  
	// set get方法省略...
}
  1. Java程序:
@Test  
public void testInsertCarByPOJO() {  
    // 创建POJO,封装数据  
    Car car = new Car();  
    car.setCarNum("103");  
    car.setBrand("奔驰C200");  
    car.setGuidePrice(33.23);  
    car.setProduceTime("2020-10-11");  
    car.setCarType("燃油车");  
    // 获取SqlSession对象  
    SqlSession sqlSession = SqlSessionUtil.openSession();  
    // 执行SQL,传数据  
    int count = sqlSession.insert("insertCarByPOJO", car);  
    System.out.println("插入了几条记录" + count);  
}
  1. SQL语句:
<insert id="insertCarByPOJO">
<!--#{} 里写的是POJO的属性名-->
insert into t_car(car_num,brand,guide_price,produce_time,car_type) 
	values
(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>

#{} 里写的是POJO的属性名,如果写成其他的会有问题吗?

<insert id="insertCarByPOJO">
<!--#{} 里写的是POJO的属性名-->
insert into t_car(car_num,brand,guide_price,produce_time,car_type) 
	values
(#{kk},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>

报错:
image.png

错误信息中描述:在Car类中没有找到a属性的getter方法。
修改POJO类Car的代码,只将getCarNum()方法名修改为getA(),其他代码不变,如下:

image.png

运行:

image.png

经过测试得出结论:

如果采用map集合传参,#{} 里写的是map集合的key,如果key不存在不会报错,数据库表中会插入NULL。
如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get方法不存在会报错。

注意:其实传参数的时候有一个属性parameterType,这个属性用来指定传参的数据类型,不过这个属性是可以省略的。

<insert id="insertCar" parameterType="java.util.Map">  
    insert into cars(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})</insert>  
  
<insert id="insertCarByPOJO" parameterType="com.rainsoul.mybatis.pojo.Car">  
    insert into cars(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})</insert>

当占位符只有一个的时候,#{} 里面的内容可以随便写。

2.3delete

需求:根据car_num进行删除。

SQL语句这样写:

<delete id="deleteByCarNum">
	delete from t_car where car_num = #{SuiBianXie}
</delete>

Java程序这样写:

@Test  
public void testDeleteByCarNum(){  
    // 获取SqlSession对象  
    SqlSession sqlSession = SqlSessionUtil.openSession();  
    // 执行SQL语句  
    int count = sqlSession.delete("deleteByCarNum", "102");  
    System.out.println("删除了几条记录:" + count);  
}

2.4update

SQL语句如下:

<update id="updateCarByPOJO">  
    update cars    
	    set car_num      = #{carNum},        
	    brand        = #{brand},        
	    guide_price  = #{guidePrice},        
	    produce_time = #{produceTime},        
	    car_type     = #{carType}    
where id = #{id}</update>

Java代码如下:

@Test  
public void testUpdateCarByPOJO(){  
    // 准备数据  
    Car car = new Car();  
    car.setId(10L);  
    car.setCarNum("102");  
    car.setBrand("比亚迪汉");  
    car.setGuidePrice(30.23);  
    car.setProduceTime("2018-09-10");  
    car.setCarType("电车");  
    // 获取SqlSession对象  
    SqlSession sqlSession = SqlSessionUtil.openSession();  
    // 执行SQL语句  
    int count = sqlSession.update("updateCarByPOJO", car);  
    System.out.println("更新了几条记录:" + count);  
}

运行前:
image.png

运行后:
image.png

当然了,如果使用map传数据也是可以的。

2.5select

select语句和其它语句不同的是:查询会有一个结果集。看mybatis是怎么处理结果集的!!!

2.5.1查询一条数据

需求:查询id为1的Car信息。

SQL语句:

<select id="selectCarById">
	select * from t_car where id = #{id}
</select>

Java程序:

@Test

public void testSelectCarById(){
	// 获取SqlSession对象
	SqlSession sqlSession = SqlSessionUtil.openSession();
	// 执行SQL语句
	Object car = sqlSession.selectOne("selectCarById", 1);
	System.out.println(car);
}
Error querying database. Cause: org.apache.ibatis.executor.ExecutorException:

A query was run and no Result Maps were found for the Mapped Statement 'car.selectCarById'. 【翻译】:对于一个查询语句来说,没有找到查询的结果映射。

It's likely that neither a Result Type nor a Result Map was specified. 【翻译】:很可能既没有指定结果类型,也没有指定结果映射。

以上的异常大致的意思是:对于一个查询语句来说,你需要指定它的“结果类型”或者“结果映射”。 所以说,你想让mybatis查询之后返回一个Java对象的话,至少你要告诉mybatis返回一个什么类型的Java对象,可以在select标签中添加resultType属性,用来指定查询要转换的类型:

<select id="selectCarById" resultType="com.powernode.mybatis.pojo.Car">
	select * from t_car where id = #{id}
</select>

运行结果:
image.png

运行后之前的异常不再出现了,这说明添加了resultType属性之后,解决了之前的异常,可以看出resultType是不能省略的。
仔细观察控制台的日志信息,奇怪的是返回的Car对象,只有id和brand两个属性有值,其它属性的值都是null,这是为什么呢?我们来观察一下查询结果列名和Car类的属性名是否能一一对应:

查询结果集的列名:id, car_num, brand, guide_price, produce_time, car_type
Car类的属性名:id, carNum, brand, guidePrice, produceTime, carType

通过观察发现:只有id和brand是一致的,其他字段名和属性名对应不上,这是不是导致null的原因呢?我们尝试在sql语句中使用as关键字来给查询结果列名起别名试试:

<select id="selectCarById" resultType="com.rainsoul.mybatis.pojo.Car">  
	select id,           
	    car_num      as carNum,           
	    brand,           
	    guide_price  as guidePrice,           
	    produce_time as produceTime,           
	    car_type     as carType    
	from cars    
	where id = #{id}
</select>

image.png

通过测试得知,如果当查询结果的字段名和java类的属性名对应不上的话,可以采用as关键字起别名,当然还有其它解决方案。

2.5.2查询多条数据

需求:查询所有的Car信息。

虽然结果是List集合,但是resultType属性需要指定的是List集合中元素的类型。虽然结果是List集合,但是resultType属性需要指定的是List集合中元素的类型

SQL语句:

<select id="selectCarAll" resultType="com.rainsoul.mybatis.pojo.Car">  
    select    id, 
    car_num as carNum, brand, 
    guide_price as guidePrice,    
    produce_time as produceTime, 
    car_type as carType    
    from    cars
</select>

Java代码:

@Test  
public void testSelectCarAll(){  
    // 获取SqlSession对象  
    SqlSession sqlSession = SqlSessionUtil.openSession();  
    // 执行SQL语句  
    List<Object> cars = sqlSession.selectList("selectCarAll");  
    // 输出结果  
    cars.forEach(System.out::println);  
}

2.6关于SQL Mapper的namespace

在MyBatis框架中,配置文件中的namespace属性用于指定映射文件(Mapper XML)的命名空间,其作用包括:

  1. 命名空间区分:一个MyBatis的配置文件可以包含多个Mapper XML文件,每个Mapper XML文件都会定义一组与数据库交互的SQL语句和映射规则。使用namespace属性可以将这些映射文件的操作区分开,避免命名冲突和混淆。

  2. 命名空间限定namespace也用于限定SQL语句和映射规则的作用范围。当在Java代码中调用MyBatis的SQL映射接口时,可以通过命名空间来定位对应的SQL语句和映射规则。

下面是一个简单的示例,演示了如何在MyBatis的配置文件中使用namespace属性:

<!-- mybatis-config.xml -->

<configuration>
    <!-- 配置数据源等其他属性 -->
    
    <!-- 指定映射文件 -->
    <mappers>
        <!-- 指定Mapper XML文件 -->
        <mapper resource="com/example/mapper/UserMapper.xml"/>
        <!-- 可以指定多个Mapper XML文件 -->
    </mappers>
</configuration>
<!-- UserMapper.xml -->

<!-- 指定命名空间 -->
<mapper namespace="com.example.mapper.UserMapper">
    
    <!-- 定义SQL语句和映射规则 -->
    <select id="getUserById" resultType="com.example.model.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
    
    <!-- 可以定义多个SQL语句和映射规则 -->
    
</mapper>

在上面的示例中,mybatis-config.xml文件中配置了一个映射文件UserMapper.xml,而UserMapper.xml中使用了namespace属性指定了命名空间为com.example.mapper.UserMapper。这样,在Java代码中调用UserMapper接口时,就可以使用这个命名空间来定位SQL语句和映射规则。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值