1. MyBatis完成CRUD 详细细节内容

@


每博一文案

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

2. MyBatis工具类SqlSessionUtil的封装

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

一般我们的工具类,的构造方法都是私有化的,防止 new 对象。

工具类中所以的方法都是静态的,直接用 类名.方法名 的方式直接调用

获取到SqlSessionFactory 对象

SQlsessionFactory对象,一个SqlSessionFactory对应一个 environment, 一个environment通常是一个数据库。所以,我们定义一个静态代码块,执行加载一次即可。

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. 准备工作

首先我们准备操作,实验的数据库,数据表。数据内容

在项目/模块当中导入相关的 jar 依赖,在pom.xml 配置相关 jar依赖的。

我们需要的依赖有:

  • mybatis依赖
  • mysql驱动依赖
  • junit依赖
  • logback依赖

<?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>
<!-- 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> <!-- 引入 junit4 依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency> <!-- 引入 logback的依赖,这个日志框架实现了slf4j 规范-->
<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放在类的根路径下

<?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>
<!-- 开启mybatis 对标准日志的实现-->
<!-- 如果导入的第三方框架的日志,没有下面这个 settings 也是可以的-->
<!-- <settings>-->
<!-- <setting name="logImpl" value="STDOUT_LOGGING"/>-->
<!-- </settings>-->
<environments default="development">
<environment id="development">
<!-- MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了。-->
<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> <!--sql映射文件创建好之后,需要将该文件路径配置到这里-->
<!-- 执行XxxMapper.xml 文件的路径-->
<!-- resource 属性自动会从类的根路径下开始查找资源-->
<!-- <mapper resource="CarMapper.xml"/>-->
<!-- <mapper resource="com/CarMapper2.xml"/>--> <!-- url属性: 从绝对路径当中加载资源。-->
<!-- 语法格式:file:///绝对路径-->
<!-- <mapper url="file:///e:/CarMapper.xml"></mapper>-->
<mapper resource="CarMapper.xml"></mapper>
</mappers>
</configuration>

同时需要配置 MyBatis 的核心配置文件,告诉 MyBatis 要使用哪个 XxxMapper .xml SQL 语句的映射文件。

  • CarMapper.xml放在类的根路径下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace先随意写一个-->
<mapper namespace="rainbowsea"> </mapper>
  • logback.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> <!--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>

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

这样写的问题是:

值,显然是写死到配置文件当中了

这个实际开发中是不存在的

一定是前端 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 语句

这里的 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">
<!--namespace先随意写一个-->
<mapper namespace="rainbowsea"> <!-- insert语句,id是这个条SQL语句的唯一标识,这个id就代表了这条SQL语句 -->
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values (null,#{k1},#{k2},#{k3},#{k4},#{k5})
<!-- map.get("fdsd") 找,结果找不到 = null-->
</insert> </mapper>

在MyBatis 中的Java程序中使用 map 可以给SQL语句的占位符传值。

Map<String,Object> 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); 方法

这里执行 **insert( ) ** 插入操作,则是用:sqlSession.insert(String var1, Object var2); 两个参数的方法,执行 insert() 插入操作,返回影响的记录条数。

// 执行sql语句
// insert方法的参数:
// 第一个参数:sqlId;从CarMapper.xml 文件中复制,的对于是insert SQL 语句的 id 信息
// 第二个参数: 封装数据的对象,这里为 Map 集合
int count = sqlSession.insert("insertCar", map);

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}

运行测试:

在以上sql语句中,可以看到#{k1} #{k2} #{k3} #{k4} #{k5}的可读性太差,为了增强可读性,我们可以将Java程序做如下修改:

对应的 CarMapper.xml SQL映射文件也是要一一对应修改。

运行测试:

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}。如下:我们测试

使用Map集合可以传参,那使用pojo(简单普通的java对象)可以完成传参。

java 程序中使用POJO类给SQL语句的占位符传值。

这里我们定义一个 名为 Car.java 的类,该类要与t_car 数据表的属性,像映射,对应上的。不可以随便定义的。

同时我们将属性定义为包装类,防止当我们数据表当中取出,获取到的数据是为 null 的时候,包装类可以赋值上,而简单类型 int 是无法赋值为 Null 的

同时一定要提供对应的 set 和 get 方法,不然 ,MyBatis 无法通过反射机制获取到相应所需要的信息的。

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})

运行测试:

 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(); }

如果我们在 XxxMapper.xml(这里是CarMapper.xml) 的SQL映射文件中 的 <insert> 标签 中的 #{ } 占位符,写的不是对应pojo(这里是 Car) 类上的属性值时,会出现什么问题,是报错,还是赋值为 Null呢?

运行测试:

报错信息:

There is no getter for property named 'xyz' in 'class com.rainbowsea.mybatis.pojo.Car'

mybatis 去找,Car类中的getXyz()方法去了,没找到,报错了。

怎么解决的?

我们在pojo(这里是 Car) 类当中加入一个 getXyz( ) 方法,方法的返回值和 原来的getCarNum( )的返回值,一样就是,方法名不同而已:就是方法名不同,返回的值还是:carNum

再运行测试;

通过这个测试,得出一个结论:

严格意义上来说,如果使用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,这个属性用来指定传参的数据类型,不过这个属性是可以省略的

3.2 delete 删除记录

需求:根据 id 删除数据,将 id = 44 的数据删除。

编写XxxMapper.xml SQL 映射的文件, 删除用 <delete> 标签

<!--注意: 如果占位符只有一个,那么#{}的大括号里可以随意,但是最好见名知意-->
<delete id="deleteById">
delete from t_car where id = #{id}
</delete>

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

只有一个占位符的时候,传一个值,MyBatis 可以自动载入,但是 #{} 不可以空着,要写上值

运行测试:

Java程序执行,删除操作,用sqlSession.delete("Id", 值) 方法,删除记录

@Test
public void testDeleteById() {
SqlSession sqlSession = SqlSessionUtil.openSession(); // 执行SQL语句
sqlSession.delete("deleteById",44); // 如果只要一个值的时候,就不需要对应上的的 Object 类型了
sqlSession.commit(); // 提交
sqlSession.close(); // 关闭
}

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 映射的文件,修改用 <update> 标签

	<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", 值) 方法,修改记录

   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 文件当中编写,对应的查询语句,查询用 <select> 标签。

运行测试:

因为查询,没有修改的操作,是不需要事务操作的,所以我们不同提交数据,给数据库。

这里我们查询的是一条记录,用 sqlSession.selectOne("id") 方法,返回一个 映射对象。

报错信息: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对象,可以在<select>标签中添加 resultType 属性,所赋值的对象是:全限定类名 ,用来指定查询要转换的类型:

需要特别注意的是:

select 标签中给的resultType属性,这个属性用来告诉mybatis,查询结果封装什么类型的Java对象

resultType通常写的是:全限定类名

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

我们再次运行:

运行后之前的异常不再出现了,这说明添加了resultType属性之后,解决了之前的异常,可以看出resultType是不能省略的。

仔细观察控制台的日志信息,不难看出,结果查询出了一条。并且每个字段都查询的到值了:

但是奇怪的是返回的Car对象,只有 id 和 brand 两个属性有值,其它属性的值都是 null,

这是为什么呢?我们来观察一下查询结果列名和Car类的属性名是否能一一对应:

通过观察发现:只有 id 和 brand 是一致的,其他字段名和属性名对应不上,这就是导致null的原因了?我们可以在sql语句中使用 as 关键字来给查询结果列名起别名的方式,让它们两者保持一致的关系。

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

3.4.6 select 查询多条记录

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

编写对应的SQL语句,在 XxxMapper.xml SQl语句映射文件当中。

同样我们需要使用上 as 关键字,定义别名,使其Java程序和数据库的字段名两者之间的字段保持一致。

	<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 集合,存储着我们的查询结果集

如果是返回的是键值对 的话,我们还可以用 sqlSession.selectMap("id") 方法 返回的是一个 Map 集合

运行结果:

   <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. 关于SQL Mapper 的 namespace 的使用方式

在SQL Mapper配置文件中 标签的 namespace 属性可以翻译为命名空间,这个命名空间主要是为了防止sqlId冲突的。

我们在创建一个 UserMapper.xml 的SQL 语句的映射文件,同样将其 namespace = "rainbowsa" 这个值,同时两个配置文件当中都有同一个:select 查询语句,同时 id 都为 selectAll 。运行看看,存在什么问题?

<?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="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文件中。

<?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>
<!-- 开启mybatis 对标准日志的实现-->
<!-- 如果导入的第三方框架的日志,没有下面这个 settings 也是可以的-->
<!-- <settings>-->
<!-- <setting name="logImpl" value="STDOUT_LOGGING"/>-->
<!-- </settings>-->
<environments default="development">
<environment id="development">
<!-- MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了。-->
<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> <!--sql映射文件创建好之后,需要将该文件路径配置到这里-->
<!-- 执行XxxMapper.xml 文件的路径-->
<!-- resource 属性自动会从类的根路径下开始查找资源-->
<!-- <mapper resource="CarMapper.xml"/>-->
<!-- <mapper resource="com/CarMapper2.xml"/>--> <!-- url属性: 从绝对路径当中加载资源。-->
<!-- 语法格式:file:///绝对路径-->
<!-- <mapper url="file:///e:/CarMapper.xml"></mapper>-->
<mapper resource="CarMapper.xml"></mapper>
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>

编写Java代码如下:

 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(); }

运行报错:

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" 命名空间的值。

同时编写Java程序的时候,使用上 namespace="rainbowsea2"的命名空间。

查询成功:

@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. 总结:

  1. 在sql语句中使用 #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符

  2. 在mybatis当中不能使用 ? 占位符,必须使用 #{ } 来代替JDBC当中的 ?

    #{ } 和JDBC当中的 ? 是等效的。

  3. { } 不可以空着,就算是只有一个传值,也不可以空着,随便写,都不可以空着。

  4. pojo 对象的数据表 ORM 映射的 类对象,一定要提供对应的 set 和 get 方法,不然 ,MyBatis 无法通过反射机制获取到相应所需要的信息的。 注意:占位符#{ }, 大括号里面写:pojo类的属性名

  5. 如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get方法不存在会报错。

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

  7. 添加/插入,执行 sqlSession.insert("Id", car); 方法

  8. Java程序执行,删除操作,用sqlSession.delete("Id", 值) 方法,删除记录,只有一个占位符的时候,传一个值,MyBatis 可以自动载入,但是 #{} 不可以空着,要写上值

  9. Java程序执行,修改/更新数据操作,用sqlSession.update("Id", 值) 方法,修改记录

  10. 因为查询,没有修改的操作,是不需要事务操作的,所以我们不同提交数据,给数据库。

    这里我们查询的是一条记录,用 sqlSession.selectOne("id") 方法,返回一个 映射对象。

  11. 你想让mybatis查询之后返回一个Java对象的话,至少你要告诉mybatis返回一个什么类型的Java对象,可以在<select>标签中添加 resultType 属性,所赋值的对象是:全限定类名 ,用来指定查询要转换的类型:

 select 查询时,需要 pojo的类当中的映射的类对象中的属性名要与 对应数据表中的字段名一致,才能赋值成功,不然为 Null。可以使用  as 关键字,定义别名的方式,解决。后面有更好的解决方式。
  1. 我们查询的是多条记录,用 sqlSession.selectList("id") 方法,返回一个 List 集合,存储着我们的查询结果集。

  2. 如果是返回的是键值对 的话,我们还可以用 sqlSession.selectMap("id") 方法 返回的是一个 Map 集合

  3. 实际上,本质上,mybatis中的 sqlId 的完整写法: namespace.id ,注意,之后都这么写了,这是完整正确的写法。

在Java程序当中的写法:
// 执行SQL语句
List<Car> cars = sqlSession.selectList("rainbowsea2.selectAll");
实际上,本质上,mybatis中的sqlId的完整写法: namespace.id ,注意,之后都这么写了,这是完整正确的写法。

  1. 关于 MyBatis 的 CRUD 是重点内容,需要熟练掌握住。

6. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

MyBatis完成CRUD 详细细节内容的更多相关文章

  1. 手把手Maven搭建SpringMVC+Spring+MyBatis框架(超级详细版)

    手把手Maven搭建SpringMVC+Spring+MyBatis框架(超级详细版) SSM(Spring+SpringMVC+Mybatis),目前较为主流的企业级架构方案.标准的MVC设计模式, ...

  2. MyBatis:CRUD功能

    在前面已经自动生成了mapper和pojo,接下来我们实现mybatis的CRUD功能,先新建service.controller层的方法. 这里的sid是一个开源的id生成类,写完后,我们还需要在启 ...

  3. struts2 + spring + mybatis 框架整合详细介绍

    struts2 + spring + mybatis  框架整合详细介绍 参考地址: https://blog.csdn.net/qq_22028771/article/details/5149898 ...

  4. Mybatis的CRUD案例

    一.Mybatis增删改查案例 上一节<Mybatis入门和简单Demo>讲了如何Mybatis的由来,工作流程和一个简单的插入案例,本节主要继上一讲完整的展示Mybatis的CRUD操作 ...

  5. 【MyBatis】MyBatis实现CRUD操作

    1.实现基本CRUD功能 使用MyBatis对数据完整的操作,也就是CRUD功能的实现.根据之前的内容,要想实现CRUD,只需要进行映射文件的配置. 范例:修改EmpMapper.xml文件,实现CR ...

  6. SpringBoot 整合 Mybatis 进行CRUD测试开发

    今天来和大家分享下 Spring Boot 整合 MyBatis 的 CRUD 测试方法开发.因为 MyBaits 有两种开发形式,一种基于注解,一种基于 xml . SpringBoot配置文件也有 ...

  7. 基于mybatis的CRUD

    u  基于Mybatis的CRUD u  掌握MyBatis的结果类型-resultMap和resultType u  掌握MyBatis的参数类型 u  掌握#和$两种语法 1      基于myb ...

  8. 05 Mybatis的CRUD操作和Mybatis连接池

    1.CRUD的含义 CRUD是指在做计算处理时的增加(Create).读取(Retrieve)(重新得到数据).更新(Update)和删除(Delete)几个单词的首字母简写.主要被用在描述软件系统中 ...

  9. 03 Mybatis:05.使用Mybatis完成CRUD

    mybatis框架:共四天 明确:我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式.不管使用XML还是注解配置. 第二天:mybatis基本使用 mybatis的单表crud操作 ...

  10. mybatis(CRUD)

    3.mybatis(CRUD) 有了mybatis,我们要对数据库进行增删改查只需要操作接口和mapper.xml文件,然后进行测试就可以了. 实例代码如下: 接口 public interface ...

随机推荐

  1. pyaudio音频录制python

    python3.7不支持pyaudio pip在线安装 whl下载地址:https://github.com/intxcc/pyaudio_portaudio/releases 下载后使用pip离线安 ...

  2. 力扣181(MySQL)- 超过经理收入的员工(简单)

    题目: 表:Employee 编写一个SQL查询来查找收入比经理高的员工. 以 任意顺序 返回结果表. 查询结果格式如下所示. 示例 1:  解题思路: 一.[子查询] 先通过子查询找到当前员工的经理 ...

  3. 如何使用 Serverless Devs 部署静态网站到函数计算

    ​简介:手把手教你:如何使用 Serverless Devs 部署静态网站到函数计算. 前言 公司经常有一些网站需要发布上线,对比了几款不同的产品后,决定使用阿里云的函数计算(FC)来托管构建出来的静 ...

  4. [JDBC] Kettle on MaxCompute 使用指南

    简介: Kettle是一款开源的ETL工具,纯Java实现,可以在Windows.Unix和Linux上运行,提供图形化的操作界面,可以通过拖拽控件的方式,方便地定义数据传输的拓扑 .基本讲介绍基于K ...

  5. [GPT] export, export default, import, module.exports, require

    ES6 规范:export 和 import 配对 import 的 {} 大括号里面指定要从其他模块导入的变量名, 如果 export 命令没有写 default,那么 import {} 大括号里 ...

  6. 运行模型对比 gemma:7b, llama2, mistral, qwen:7b

    [gemma:2b] total duration: 1m5.2381509sload duration: 530.9µsprompt eval duration: 110.304msprompt e ...

  7. STM32【HAL库】使用外部SRAM程序

    #include <board.h> #ifdef BSP_USING_SRAM #include <drv_common.h> #include <rtthread.h ...

  8. Util 应用框架 UI 全新升级

    Util UI 已经开发多年, 并在多家公司的项目使用. 不过一直以来, Util UI 存在一些缺陷, 始终未能解决. 最近几个月, Util 团队下定决心, 终于彻底解决了所有已知缺陷. Util ...

  9. 【GUI软件】抖音搜索结果批量采集,支持多个关键词、排序方式、发布时间筛选等!

    目录 一.背景介绍 1.1 爬取目标 1.2 演示视频 1.3 软件说明 二.代码讲解 2.1 爬虫采集模块 2.2 软件界面模块 2.3 日志模块 三.获取源码及软件 一.背景介绍 1.1 爬取目标 ...

  10. 【GUI开发】用python爬YouTube博主信息,并开发成exe软件!

    目录 一.背景介绍 二.代码讲解 2.1 爬虫 2.2 tkinter界面 2.3 存日志 三.说明 一.背景介绍 你好,我是@马哥python说,一名10年程序猿. 最近我用python开发了一个G ...