伤心客 发表于 2024-5-30 11:59:39

MyBatis完成CRUD 具体细节内容

1. MyBatis完成CRUD 具体细节内容

@
目录

[*]1. MyBatis完成CRUD 具体细节内容
[*]每博一文案
[*]2. MyBatis工具类SqlSessionUtil的封装
[*]3. 预备工作

[*]3.1 insert 添加/插入记录
[*]3.2 delete 删除记录
[*]3.3 update 修改记录
[*]3.4 select 查询记录

[*]3.4.5 select 查询一条记录
[*]3.4.6 select 查询多条记录


[*]4. 关于SQLMapper 的 namespace 的使用方式
[*]5. 总结:
[*]{ } 不可以空着,就算是只有一个传值,也不可以空着,随便写,都不可以空着。
[*]6. 末了:

每博一文案

书再难背,也就几个月,跑步再累也就五分钟,题目再难,
也会有解法,累了就听听歌,散散步,出去走走。所以,你不会
且觉得难的东西一定不要躲,先弄明白,后精湛,你就比别人优秀。
                                ——————《罗翔老师》2. MyBatis工具类SqlSessionUtil的封装

我们可以先将 SqlSession 对象的获取,封装成一个工具类来使用,方便一些。关于 SqlSession 对象的获取的具体内容,大家可以移步至:✏️✏️✏️ 初始MyBatis ,具体步骤运行第一个MyBatis程序,同时对应步骤MyBatis底层分析-CSDN博客

一般我们的工具类,的构造方法都是私有化的,防止 new 对象。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623127-492129551.png
工具类中所以的方法都是静态的,直接用 类名.方法名 的方式直接调用
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623260-1727693216.png
获取到SqlSessionFactory 对象
SQlsessionFactory对象,一个SqlSessionFactory对应一个 environment, 一个environment通常是一个数据库。所以,我们定义一个静态代码块,执行加载一次即可。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623477-1379271404.png
package com.rainbowsea.mybatis.utils;


import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;

public class SqlSessionUtil {
    // 工具类的构造方法一般都是私有话化的
    // 工具类中所有的方法都是静态的,直接类名即可调用,不需要 new 对象
    // 为了防止new对象,构造方法私有化。

    private SqlSessionUtil() {

    }



    private static SqlSessionFactory sessionFactory = null;

    // 静态代码块,类加载时执行
    // SqlSessionUtil 工具类在进行第一次加载的时候,解析mybatis-config.xml 文件,创建SqlSessionFactory对象。
    static {
      // 获取到SqlSessionFactoryBuilder 对象
      SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

      // 获取到SqlSessionFactory 对象
      // SQlsessionFactory对象,一个SqlSessionFactory对应一个 environment, 一个environment通常是一个数据库
      try {
            sessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
      } catch (IOException e) {
            throw new RuntimeException(e);
      }

    }

    /**
   * 获取会话对象
   * @return SqlSession
   */
    public static SqlSession openSession() {
      // 获取到 SqlSession 对象
      SqlSession sqlSession = sessionFactory.openSession();
      return sqlSession;
    }
}3. 预备工作

首先我们预备操作,实验的数据库,数据表。数据内容
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623463-237859902.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623465-1104551926.png
在项目/模块当中导入相关的 jar 依靠,在pom.xml 配置相关 jar依靠的。
我们需要的依靠有:


[*]mybatis依靠
[*]mysql驱动依靠
[*]junit依靠
[*]logback依靠
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623216-400240231.png
<?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.rainbowsea</groupId>
    <artifactId>mybatis-002-crud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
      <maven.compiler.source>17</maven.compiler.source>
      <maven.compiler.target>17</maven.compiler.target>
    </properties>


    <dependencies>

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

      <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
      </dependency>


      <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>
      </dependency>
    </dependencies>




</project>其次就是:


[*]mybatis-config.xml放在类的根路径下
[*]CarMapper.xml放在类的根路径下
[*]logback.xml放在类的根路径下
[*]提供com.powernode.mybatis.utils.SqlSessionUtil工具类
[*]创建测试用例:com.powernode.mybatis.CarMapperTest
上述内容,为什么放在类的根路径下(resources) 就是为了提高项目的可移植性。具体内容,大家可以移步至:✏️✏️✏️初始MyBatis ,具体步骤运行第一个MyBatis程序,同时对应步骤MyBatis底层分析-CSDN博客


[*]mybatis-config.xml放在类的根路径下
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623247-547407942.png
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
   
   
   
   
   
    <environments default="development">
      <environment id="development">
            
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="MySQL123"/>
            </dataSource>
      </environment>
    </environments>


    <mappers>

      
      
      
      
      

      
      
      
      <mapper resource="CarMapper.xml"></mapper>
    </mappers>
</configuration>同时需要配置 MyBatis 的核心配置文件,告诉 MyBatis 要使用哪个 XxxMapper .xml SQL 语句的映射文件。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623261-1539390756.png

[*]CarMapper.xml放在类的根路径下
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623253-133497172.png


[*]logback.xml放在类的根路径下
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623270-844844870.png
<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false">
   
    <appender name="STDOUT" >
      <encoder >
            
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      </encoder>
    </appender>

   
    <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"/>

   
    <root level="DEBUG">
      <appender-ref ref="STDOUT"/>
      <appender-ref ref="FILE"/>
    </root>

</configuration>3.1 insert 添加/插入记录

分析以下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">


<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>https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623341-1461424399.png
这样写的问题是:
值,显然是写死到配置文件当中了
这个实际开发中是不存在的
肯定是前端 form 表单提交过来数据,然后将值传给 sql 语句
SQL语句中的值不应该写死,值应该是用户提供的。之前的JDBC代码是这样写的:
// JDBC中使用 ? 作为占位符。那么MyBatis中会使用什么作为占位符呢?
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,"燃油车");在JDBC当中占位符采用的是?,在mybatis当中是什么呢?
和?等效的写法是: #{}在mybatis当中不能使用 ? 占位符,必须使用 #{ } 来代替JDBC当中的?
#{ }和JDBC当中的 ? 是等效的。
在MyBatis 中,的Java程序中,将数据放到Map集合中
在sql语句中使用 #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符
我们在 XxxMapper.xml SQL 映射文件当中,使用上 #{ } 重新编写 对于的 insert SQL 语句
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623133-1887440537.png
这里的 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="rainbowsea">


        <insert id="insertCar">
                insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
                values (null,#{k1},#{k2},#{k3},#{k4},#{k5})

        </insert>

</mapper>在MyBatis 中的Java程序中使用 map 可以给SQL语句的占位符传值。
Map map = new HashMap();
map.put("k1","111");
map.put("k2","比亚迪汉");
map.put("k3",10.0);
map.put("k4","2020-11-11");
map.put("k5","电车");添加/插入,执行 sqlSession.insert("Id", car); 方法
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623257-697111880.png
这里执行 **insert( ) ** 插入操作,则是用:sqlSession.insert(String var1, Object var2); 两个参数的方法,执行 insert() 插入操作,返回影响的记录条数。
// 执行sql语句
// insert方法的参数:
// 第一个参数:sqlId;从CarMapper.xml 文件中复制,的对于是insert SQL 语句的 id 信息
// 第二个参数: 封装数据的对象,这里为 Map 集合
int count = sqlSession.insert("insertCar", map);https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623143-632033594.png
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values (null,#{fdsd},#{k2},#{k3},#{k4},#{k5})
注意:#{这里写什么?写map集合的key,如果key不存在,获取的是null}运行测试:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623271-412896961.png
在以上sql语句中,可以看到#{k1} #{k2} #{k3} #{k4} #{k5}的可读性太差,为了增强可读性,我们可以将Java程序做如下修改:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623152-1329085238.png
对应的 CarMapper.xml SQL映射文件也是要逐一对应修改。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623479-1102713526.png
运行测试:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623213-1659775875.png
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values (null,#{fdsd},#{k2},#{k3},#{k4},#{k5})
留意:#{这里写什么?写map集合的key,如果key不存在,获取的是null}。如下:我们测试
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623472-1476852025.png
使用Map集合可以传参,那使用pojo(简朴普通的java对象)可以完成传参。
java 程序中使用POJO类给SQL语句的占位符传值。
这里我们定义一个 名为 Car.java 的类,该类要与t_car 数据表的属性,像映射,对应上的。不可以随便定义的。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623349-1694006520.png
同时我们将属性定义为包装类,防止当我们数据表当中取出,获取到的数据是为 null 的时候,包装类可以赋值上,而简朴类型 int 是无法赋值为 Null 的
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623277-1391281965.png
同时肯定要提供对应的 set 和 get 方法,不然 ,MyBatis 无法通过反射机制获取到相应所需要的信息的。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623163-924113977.png
package com.rainbowsea.mybatis.pojo;

public class Car {
    //数据表当中的字段应该和pojo类的属性一一对应
    // 建议使用包装类,这样可以防止 null 的问题:int = null; 不行,Int = null 可以
    private Long id;
    private String carNum;
    private String brand;
    private Double guiderPrice;
    private String produceTime;
    private String carType;

    public Car() {
    }

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


    @Override
    public String toString() {
      return "Car{" +
                "id=" + id +
                ", carNum='" + carNum + '\'' +
                ", brand='" + brand + '\'' +
                ", guiderPrice=" + guiderPrice +
                ", produceTime='" + produceTime + '\'' +
                ", carType='" + carType + '\'' +
                '}';
    }


    public Long getId() {
      return id;
    }

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

    public String getCarNum() {
      return carNum;
    }

/*    public String getXyz() {
      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 getGuiderPrice() {
      return guiderPrice;
    }

    public void setGuiderPrice(Double guiderPrice) {
      this.guiderPrice = guiderPrice;
    }

    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;
    }
}java 程序中使用POJO类给SQL语句的占位符传值:
// 封装数据
Car car = new Car(null, "333", "比亚迪泰", 30.0, "2020-11-11", "新能源");
留意:占位符#{ }, 大括号内里写:pojo类的属性名
insert into t_car(id,car_num,bread,guider_prive,produce_time,car_type)
values(null,#{xyz},#{brand},#{guiderPrice},#{produceTime},#{carType})
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623476-2003867658.png
运行测试:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623275-1746571028.png
public void testInsertCarByPOJO() {
      SqlSession sqlSession = SqlSessionUtil.openSession();

      // 封装数据
      Car car = new Car(null, "333", "比亚迪泰", 30.0, "2020-11-11", "新能源");

      // 执行SQL
      int count = sqlSession.insert("insertCar", car); // ORM       // 对应XxxMapper.xml 上的id
      System.out.println(count);

      sqlSession.commit();
      sqlSession.close();

    }https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623494-2075934888.png
如果我们在 XxxMapper.xml(这里是CarMapper.xml) 的SQL映射文件中 的标签 中的 #{ } 占位符,写的不是对应pojo(这里是 Car) 类上的属性值时,会出现什么问题,是报错,还是赋值为 Null呢?
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623253-65980010.png
运行测试:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623554-1563805399.png
报错信息:
There is no getter for property named 'xyz' in 'class com.rainbowsea.mybatis.pojo.Car'
mybatis 去找,Car类中的getXyz()方法去了,没找到,报错了。
怎么解决的?
我们在pojo(这里是 Car) 类当中参加一个 getXyz( ) 方法,方法的返回值和 原来的getCarNum( )的返回值,一样就是,方法名不同而已:就是方法名不同,返回的值还是:carNum
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623470-1571014454.png
再运行测试;
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623465-760048197.png
通过这个测试,得出一个结论:
严格意义上来说,如果使用POJO对象通报值的话,#{}这个大括号中i给你到底写什么?
写的是对应的属性的 get方法的方法名去掉 get,然后将剩下的单词字母小写,然后放进去。
例如:getUsername() ---> #{username}
例如: getEmail() ---> #{email}
也就是说MyBatis在底层,传值的时候,先要获取值,怎么获取的?
调用了pojo对象的get方法,例如:car.getCarNum(); car.getCarType(), car.getBreand() 方法
经过测试得出结论:
如果采用map集合传参,#{} 里写的是map集合的key,如果key不存在不会报错,数据库表中会插入NULL。
如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get方法不存在会报错。
留意:实在传参数的时候有一个属性 parameterType,这个属性用来指定传参的数据类型,不外这个属性是可以省略的
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623401-1388172536.png
3.2 delete 删除记录

需求:根据 id 删除数据,将 id = 44 的数据删除。
编写XxxMapper.xml SQL 映射的文件, 删除用标签
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623462-929556481.png
        <delete id="deleteById">
                delete from t_car where id = #{id}
        </delete>留意:当占位符只有一个的时候,#{} 内里的内容可以随便写。
只有一个占位符的时候,传一个值,MyBatis 可以自动载入,但是 #{} 不可以空着,要写上值
运行测试:
Java程序执行,删除操作,用sqlSession.delete("Id", 值) 方法,删除记录
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623389-639401408.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623267-1801780344.png
@Test
    public void testDeleteById() {
      SqlSession sqlSession = SqlSessionUtil.openSession();

      // 执行SQL语句
      sqlSession.delete("deleteById",44); // 如果只要一个值的时候,就不需要对应上的的 Object 类型了
      sqlSession.commit(); // 提交
      sqlSession.close(); // 关闭
    }https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623161-905123613.png
3.3 update 修改记录

需求: 根据 id 修改某条记录
需求:修改 id=46 的Car信息,car_num为999,brand为凯美瑞,guide_price为30.00,produce_time为2020-011-11,car_type为燃油车。
编写XxxMapper.xml SQL 映射的文件,修改用标签
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623222-1277279553.png
        <update id="updateById">
                update t_car set car_num = #{carNum}, brand=#{brand}, guide_price=#{guiderPrice},produce_time=#{produceTime},
                                 car_type=#{carType} where id =#{id}
        </update>运行测试:
Java程序执行,修改/更新数据操作,用sqlSession.update("Id", 值) 方法,修改记录
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623215-580008273.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623217-693307510.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623464-1634671714.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623221-1595130671.png
   public void testUpdateById() {
      SqlSession sqlSession = SqlSessionUtil.openSession();

      Car car = new Car(46L, "999", "凯美瑞", 30.3, "1999-11-10", "燃油车");
      // 执行SQL语句
      int count = sqlSession.update("updateById", car);
      System.out.println(count);

      sqlSession.commit();
      sqlSession.close();

    }当然了,如果使用 map传数据也是可以的。
3.4 select 查询记录

3.4.5 select 查询一条记录

select语句和其它语句不同的是:查询会有一个结果集。
需求:根据id 查询对应的一条记录,这里我们查询 id = 1 的记录信息。
在XxxMapper.xml 文件当中编写,对应的查询语句,查询用标签。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623353-1363841828.png
运行测试:
因为查询,没有修改的操作,是不需要事务操作的,所以我们不同提交数据,给数据库。
这里我们查询的是一条记录,用 sqlSession.selectOne("id")方法,返回一个 映射对象。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623371-537213191.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623155-208638941.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623365-418657076.png
报错信息:Error querying database.Cause: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'rainbowsea.selectById'.It's likely that neither a Result Type nor a Result Map was specified.
以上的异常大致的意思是:对于一个查询语句来说,你需要指定它的“结果类型”或者“结果映射”。
所以说,你想让mybatis查询之后返回一个Java对象的话,至少你要告诉mybatis返回一个什么类型的Java对象,可以在标签中添加 resultType 属性,所赋值的对象是:全限定类名 ,用来指定查询要转换的类型:
需要特别留意的是:
select 标签中给的resultType属性,这个属性用来告诉mybatis,查询结果封装什么类型的Java对象
resultType通常写的是:全限定类名
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623479-1830905345.png
        <select id="selectById" resultType="com.rainbowsea.mybatis.pojo.Car">
                select id,car_num as carNum, brand, guide_price as guiderPrice,
                produce_time as produceTime,
                car_type as carType
                from t_car
                where id= #{id}
        </select>我们再次运行:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623476-498005221.png
运行后之前的异常不再出现了,这说明添加了resultType属性之后,解决了之前的异常,可以看出resultType是不能省略的。
仔细观察控制台的日记信息,不丢脸出,结果查询出了一条。而且每个字段都查询的到值了:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623218-555372478.png
但是奇怪的是返回的Car对象,只有 id 和 brand 两个属性有值,其它属性的值都是 null,
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623445-117584684.png
这是为什么呢?我们来观察一下查询结果列名和Car类的属性名是否能逐一对应:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623487-1646413071.png
通过观察发现:只有 id 和 brand 是同等的,其他字段名和属性名对应不上,这就是导致null的原因了?我们可以在sql语句中使用 as 关键字来给查询结果列名起别名的方式,让它们两者保持同等的关系。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623221-1905190876.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623219-1117843912.png
        <select id="selectById" resultType="com.rainbowsea.mybatis.pojo.Car">
                select id,car_num as carNum, brand, guide_price as guiderPrice,
                produce_time as produceTime,
                car_type as carType
                from t_car
                where id= #{id}
        </select>https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623156-1801601740.png
3.4.6 select 查询多条记录

需求:查询全部的Car信息。
编写对应的SQL语句,在 XxxMapper.xml SQl语句映射文件当中。
同样我们需要使用上 as 关键字,定义别名,使其Java程序和数据库的字段名两者之间的字段保持同等。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623393-2049256282.png
        <select id="selectAll" resultType="com.rainbowsea.mybatis.pojo.Car">
                select
                     id,car_num as carNum, brand, guide_price as guiderPrice,
                           produce_time as produceTime,
                           car_type as carType
                from
                     t_car

        </select>Java代码如下:
这里,因为我们查询的是多条记录,用 sqlSession.selectList("id")方法,返回一个 List 集合,存储着我们的查询结果集。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623459-1044989015.png
如果是返回的是键值对 的话,我们还可以用 sqlSession.selectMap("id") 方法 返回的是一个 Map 集合
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623220-934712991.png
运行结果:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623217-1182897442.png
   <select id="selectAll" resultType="com.rainbowsea.mybatis.pojo.Car">
      select
             id,car_num as carNum, brand, guide_price as guiderPrice,
            produce_time as produceTime,
            car_type as carType
      from
             t_car

   </select>

List<Car> cars = sqlSession.selectList("selectAll");
注意: resultType 还是指定封装的结果集的类型,不是指定List类型,是指定List集合中元素的类型
selectList 方法,mybatis通过这个方法就可以得知你需要一个List集合,它会自动给你返回一个List集合4. 关于SQLMapper 的 namespace 的使用方式

在SQL Mapper配置文件中标签的 namespace 属性可以翻译为定名空间,这个定名空间主要是为了防止sqlId冲突的。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623473-1501016010.png
我们在创建一个 UserMapper.xml 的SQL 语句的映射文件,同样将其 namespace = "rainbowsa" 这个值,同时两个配置文件当中都有同一个:select 查询语句,同时 id 都为 selectAll 。运行看看,存在什么问题?
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623110-1224057026.png
<?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="rainbowsea">

        <select id="selectAll" resultType="com.rainbowsea.mybatis.pojo.Car">
                select
                        id,car_num as carNum, brand, guide_price as guiderPrice,
                        produce_time as produceTime,
                        car_type as carType
                from
                        t_car

        </select>

</mapper>将它们都配置到:将CarMapper.xml 和UserMapper.xml 都配置到mybatis-config.xml文件中。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623266-164710587.png
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
   
   
   
   
   
    <environments default="development">
      <environment id="development">
            
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="MySQL123"/>
            </dataSource>
      </environment>
    </environments>


    <mappers>

      
      
      
      
      

      
      
      
      <mapper resource="CarMapper.xml"></mapper>
    </mappers>
</configuration>      编写Java代码如下:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623382-1041881184.png
public void testNamespace() {
      SqlSession sqlSession = SqlSessionUtil.openSession();

      // 执行SQL语句
      // 正确的完整写法:namespace.id
      List<Car> cars = sqlSession.selectList("selectAll");

      // 遍历
      cars.forEach(car -> {
            System.out.println(car);
      });

      //sqlSession.commit();查询不用提交,没有事务问题
      sqlSession.close();

    }运行报错:
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623527-1807435303.png
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'UserMapper.xml'. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for rainbowsea.selectAll. please check CarMapper.xml and UserMapper.xml
【翻译】selectCarAll在Mapped Statements集合中不明确(请实验使用包含名称空间的全名,或重定名其中一个条目)
【大致意思是】selectCarAll重名了,你要么在selectCarAll前添加一个名称空间,要有你改个其它名字。
这里我们修改一下 UserMapper.xml 文件当中的 namespace = "rainbowsea2" 定名空间的值。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623372-727090619.png
同时编写Java程序的时候,使用上 namespace="rainbowsea2"的定名空间。
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623460-1317635123.png
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623253-1981036307.png
查询成功:
@Test
    public void testNamespace() {
      SqlSession sqlSession = SqlSessionUtil.openSession();

      // 执行SQL语句
      // 正确的完整写法:namespace.id
      List<Car> cars = sqlSession.selectList("rainbowsea2.selectAll");

      // 遍历
      cars.forEach(car -> {
            System.out.println(car);
      });

      //sqlSession.commit();查询不用提交,没有事务问题
      sqlSession.close();

    }实际上,本质上,mybatis中的 sqlId的完备写法: namespace.id ,留意,之后都这么写了,这是完备正确的写法。
5. 总结:


[*]在sql语句中使用 #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符。
[*]在mybatis当中不能使用 ? 占位符,必须使用 #{ } 来代替JDBC当中的?
#{ }和JDBC当中的 ? 是等效的。
[*]{ } 不可以空着,就算是只有一个传值,也不可以空着,随便写,都不可以空着。
[*]pojo 对象的数据表 ORM 映射的 类对象,肯定要提供对应的 set 和 get 方法,不然 ,MyBatis 无法通过反射机制获取到相应所需要的信息的。 留意:占位符#{ }, 大括号内里写:pojo类的属性名
[*]如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get方法不存在会报错。
[*]留意:实在传参数的时候有一个属性 parameterType,这个属性用来指定传参的数据类型,不外这个属性是可以省略的
[*]添加/插入,执行 sqlSession.insert("Id", car); 方法
[*]Java程序执行,删除操作,用sqlSession.delete("Id", 值) 方法,删除记录,只有一个占位符的时候,传一个值,MyBatis 可以自动载入,但是 #{} 不可以空着,要写上值
[*]Java程序执行,修改/更新数据操作,用sqlSession.update("Id", 值) 方法,修改记录
[*]因为查询,没有修改的操作,是不需要事务操作的,所以我们不同提交数据,给数据库。
这里我们查询的是一条记录,用 sqlSession.selectOne("id")方法,返回一个 映射对象。

[*]你想让mybatis查询之后返回一个Java对象的话,至少你要告诉mybatis返回一个什么类型的Java对象,可以在标签中添加 resultType 属性,所赋值的对象是:全限定类名 ,用来指定查询要转换的类型:
select 查询时,需要 pojo的类当中的映射的类对象中的属性名要与 对应数据表中的字段名一致,才能赋值成功,不然为 Null。可以使用as 关键字,定义别名的方式,解决。后面有更好的解决方式。
[*]我们查询的是多条记录,用 sqlSession.selectList("id")方法,返回一个 List 集合,存储着我们的查询结果集。
[*]如果是返回的是键值对 的话,我们还可以用 sqlSession.selectMap("id") 方法 返回的是一个 Map 集合
[*]实际上,本质上,mybatis中的 sqlId的完备写法: namespace.id ,留意,之后都这么写了,这是完备正确的写法。
在Java程序当中的写法:
   // 执行SQL语句
      List<Car> cars = sqlSession.selectList("rainbowsea2.selectAll");
实际上,本质上,mybatis中的sqlId的完整写法: namespace.id ,注意,之后都这么写了,这是完整正确的写法。https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623316-933896378.png

[*]关于 MyBatis 的 CRUD 是重点内容,需要熟练掌握住。
6. 末了:

“在这个末了的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时候再次相遇。”
https://img2024.cnblogs.com/blog/3084824/202405/3084824-20240530113623532-1312437388.gif

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: MyBatis完成CRUD 具体细节内容