准备工作
○ 创建module(Maven的普通Java模块):mybatis-002-crud
○ pom.xml
■ 打包方式jar
■ 依赖:
● mybatis依赖
● mysql驱动依赖
● junit依赖
● logback依赖
○ mybatis-config.xml放在类的根路径下
○ CarMapper.xml放在类的根路径下(一张表对应一个Mapper)
○ logback.xml放在类的根路径下
○ 提供com.sunsplanter.mybatis.utils.SqlSessionUtil工具类
○ 创建测试用例:com.sunsplanter.mybatis.CarMapperTest
1.insert(Create)
1.1使用map传参完成insert
在第一个mybatis程序中的CarMapper.xml文件中,Sql语句是写死的:
<insert id="insertCar">
//插入的东西全部写死了,但实际使用中,我们不可能预知用户需要insert的数据
//一定是通过某种方法留空,然后前端的form表单传来数据,再将数据与sql语句结合提交
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values(null,'1003','toyota',30.00,'2000-10-11','燃油车')
</insert>
在JDBC中,我们是这样留空的:
// JDBC中使用 ? 作为占位符。
String sql = "insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(?,?,?,?,?)";
在MyBatis中,我们这样做:
在Java程序中,将数据放到Map集合中
在sql语句中使用 #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符
package com.sunsplanter.mybatis;
import com.sunsplanter.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class CarMapperTest {
@Test
public void testInsertCar() {
//前端传来数据了,用map将这些数据封装起来
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语句,第一个参数是sql段的id,第二参数是要传入的对象(使用map集合给sql语句传递数据)
int count = sqlSession.insert("insertCar", map);
System.out.println("插入了几条记录:" + count);
}
}
<?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="TBD
">
<insert id="insertCar">
<!--t_car后接的参数指明要插入表中的哪个单元,而#{} 的里面必须填写map集合的key,以正确获取map的value-->
insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>
</mapper>
1.2使用POJO传参完成insert
如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get方法不存在会报错。
● 第一步:新建一个pojo包,包下定义一个pojo类Car,提供相关属性。
package com.sunsplanter.mybatis.pojo;
public class Car {
//long还是Long?若使用包装类,其提供了更多的方法可供调用,并且支持值为null的情况。
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;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCarNum() {
return carNum;
}
public void setCarNum(String carNum) {
this.carNum = carNum;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Double getGuidePrice() {
return guidePrice;
}
public void setGuidePrice(Double guidePrice) {
this.guidePrice = guidePrice;
}
public String getProduceTime() {
return produceTime;
}
public void setProduceTime(String produceTime) {
this.produceTime = produceTime;
}
public String getCarType() {
return carType;
}
public void setCarType(String carType) {
this.carType = carType;
}
}
@Test
public void testInsertCarByPOJO(){
// 创建POJO,封装数据
Car car = new Car();
//前端传来数据了,用set方法将这些数据传入POJO属性
car.setCarNum("103");
car.setBrand("奔驰C200");
car.setGuidePrice(33.23);
car.setProduceTime("2020-10-11");
car.setCarType("燃油车");
//调用封装好的方法获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执行SQL语句。第一个参数是sql段的id,第二参数是要传入的对象(使用POJO对象给sql语句传递数据)
int count = sqlSession.insert("insertCarByPOJO", car);
System.out.println("插入了几条记录" + count);
}
<insert id="insertCarByPOJO">
<!--#{} 里写的是POJO的属性名-->
insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>
2.Delete
需求:根据car_num进行删除。
@Test
public void testDeleteByCarNum(){
//调用封装好的方法获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执行SQL语句。第一个参数是sql段的id,第二个参数是要删除的“car_num”
int count = sqlSession.delete("deleteByCarNum", "102");
System.out.println("删除了几条记录:" + count);
}
<delete id="deleteByCarNum">
<!--当占位符只有一个的时候,${} 里面的内容可以随便写。-->
delete from t_car where car_num = #{SuiBianXie}
</delete>
2.1用POJO传参Update
需求:修改id=34的Car信息,car_num为102,brand为比亚迪汉,guide_price为30.23,produce_time为2018-09-10,car_type为电车
<update id="updateCarByPOJO">
update t_car set
car_num = #{carNum}, brand = #{brand},
guide_price = #{guidePrice}, produce_time = #{produceTime},
car_type = #{carType}
where id = #{id}
</update>
@Test
public void testUpdateCarById_POJO(){
// 准备数据
Car car = new Car();
car.setId(5L);
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("updateCarById_Map", car);
System.out.println("更新了几条记录:" + count);
}
2.2用Map传参Update
需求一致,XML代码也一致,仅仅是java代码改为用Map传参
@Test
public void testUpdateCarById_Map(){
//前端传来数据了,用map将这些数据封装起来
Map<String, Object> map = new HashMap<>();
map.put("id", 5L);
map.put("carNum", "104");
map.put("brand", "XiaomiSU7");
map.put("guidePrice", 18.9);
map.put("produceTime", "2024-04-01");
map.put("carType", "电动车");
//调用封装好的方法获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执行SQL语句
int count = sqlSession.update("updateCarById_Map",map);
System.out.println("更新了几条记录:" + count);
}
3.1select(Retrieve)一条
select语句和其它语句不同的是:查询会返回一个结果集ResultSet。,然而,语句是:
Object car = sqlSession.selectOne("selectCarById", 1);
因此,必须将ResultSet转化成成一个Java对象。mybatis查询之后返回一个Java对象的话,至少你要告诉mybatis返回一个什么类型的Java对象,可以在标签中添加resultType属性,用来指定查询要转换的类型:
<select id="selectCarById" resultType="com.powernode.mybatis.pojo.Car">
select * from t_car where id = #{id}
</select>
@Test
public void testSelectCarById(){
// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
//查一条记录用selectOne方法
Car car = sqlSession.selectOne("selectCarById", 1);
System.out.println(car);
}
然而,这样输出的结果是:
原因是:例如对于汽车编号这个字段,在POJO类和mapper文件中为carNum,但在数据库表中为car_num,这样当然查不到。
改为:
<!--虽然结果是List集合,但是resultType属性需要指定的是List集合中元素的类型。-->
<select id="selectCarById" resultType="com.sunsplanter.mybatis.pojo.Car">
select
<!--记得使用as起别名,让查询结果的字段名和java类的属性名对应上。
方法是:数据库中字段名 as Java中属性名-->
id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType
from
t_car
where
id = #{id}
</select>
3.1select(Retrieve)多条
- 取一条时,用selectOne方法返回ResultSet,转化成一个指定对象,这个指定对象只要定义个Car car接受即可。
取多条时,用selectList方法返回多个ResultSet转换成多个指定对象,这多个对象定义一个List来接受,否则要定义Car car1 car2…
<!--虽然结果是List集合,但是resultType属性需要指定的是List集合中元素的类型。-->
<select id="selectCarAll" resultType="com.sunsplanter.mybatis.pojo.Car">
<!--记得使用as起别名,让查询结果的字段名和java类的属性名对应上。-->
select
id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType
from
t_car
</select>
@Test
public void testSelectCarAll(){
// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执行SQL语句
List<Object> cars = sqlSession.selectList("selectCarAll");
// 输出结果
cars.forEach(car -> System.out.println(car));
}
4命名空间
在SQL Mapper配置文件中标签的namespace属性可以翻译为命名空间,这个命名空间主要是为了防止sqlId冲突的。
我们知道一张表对应一个Mapper.xml,而在程序中,仅仅以语句块的id作为辨识符,决定执行哪个语句。例如:
CarMapper1.xml:
<mapper namespace="car1">
<select id="selectCarAll" resultType="com.sunsplanter.mybatis.pojo.Car">
select
id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType
from
t_car
</select>
</mapper>
此时如有CarMapper2.xml:
<mapper namespace="car2">
<select id="selectCarAll" resultType="com.sunsplanter.mybatis.pojo.Car">
select
id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType
from
t_car
</select>
</mapper>
而代码为:
@Test
public void testNamespace(){
// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执行SQL语句
List<Object> cars = sqlSession.selectList("selectCarAll");
// 输出结果
cars.forEach(car -> System.out.println(car));
}
就会报错,因为两个Mapper中都有id为“selectCarAll”的Sql语句段,系统无法分辨执行哪一段。
解决办法:“namespace.id”
List<Object> cars = sqlSession.selectList("car2.selectCarAll");