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. 重新整理 .net core 实践篇——— 测试控制器[四十九]

    前言 其实就是官方的例子,只是在此收录整理一下. 正文 测试控制器测试的是什么呢? 测试的是避开筛选器.路由.模型绑定,就是只测试控制器的逻辑,但是不测试器依赖项. 代码部分: https://git ...

  2. linux 允许root 用户登录(旧)

    前言 旧博客迁移的内容 正文 vi /etc/ssh/sshd_config 将PermitRootLogin值改yes service sshd restart

  3. leetcode:655. 输出二叉树

    655. 输出二叉树 在一个 m*n 的二维字符串数组中输出二叉树,并遵守以下规则: 1> 行数 m 应当等于给定二叉树的高度. 2> 列数 n 应当总是奇数. 3> 根节点的值(以 ...

  4. szfpga 详细:高云1N1开发板高云gowin软件使用教程

      1.概述 国产FPGA是最近几年起来的产品,具有性价比高特点.高云FPGA,大多用在LED,电机控制,PLC设备上. 高云1N1开发板采用GW1N-LV1QN48C6/I5 FPGA器件.具有低功 ...

  5. c#采用toml做配置文件的坑过

    这几天在玩个程序,突然看到c#采用图toml文件,好用,直观,确实也简单. 不过...... github上示例写的 TOML to TomlTable TOML input file:v Enabl ...

  6. 力扣1097(MySQL)-游戏玩法分析Ⅴ(困难)

    题目: 我们将玩家的安装日期定义为该玩家的第一个登录日. 我们还将某个日期 X 的第 1 天留存时间定义为安装日期为 X 的玩家的数量,他们在 X 之后的一天重新登录,除以安装日期为 X 的玩家的数量 ...

  7. 全方位事件监控管理,阿里云日志服务Kubernetes事件中心正式上线

    2020年2月21日,阿里云日志服务Kubernetes事件中心正式上线,为Kubernetes事件提供集中化采集.存储.分析.可视化.告警等能力,帮助Kubernetes使用者快速构建准实时.高可靠 ...

  8. 实时数仓Hologres首次走进阿里淘特双11

    ​简介:这是淘特在阿里巴巴参与的第二个双11大促,大促期间累计超过上千万消费者在此买到心仪的商品,数百万家商家因为淘特而变得不同,未来,淘特也将会继续更好的服务于下沉市场,让惠民走近千万家. 2021 ...

  9. 用Multisim验证简易测谎仪

    用Multisim验证简易测谎仪 测谎仪电路如下图所示: 节点1,2之间用10M欧的电位计代表人体表电阻,原理是撒谎出汗的话,体表电阻就小.Q1,Q2构成互补音频振荡器,振荡频率由R2.C1和R12共 ...

  10. js部分数组方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...