> 文章列表 > MyBatis(十一)、MyBatis查询语句专题

MyBatis(十一)、MyBatis查询语句专题

MyBatis(十一)、MyBatis查询语句专题

准备工作:

模块名:mybatis-007-select

打包方式:jar

引入依赖:mysql驱动依赖、mybatis依赖、logback依赖、junit依赖。

引入配置文件:jdbc.properties、mybatis-config.xml、logback.xml

创建pojo类:Car

创建Mapper接口:CarMapper

创建Mapper接口对应的映射文件:com/powernode/mybatis/mapper/CarMapper.xml

创建单元测试:CarMapperTest

拷贝工具类:SqlSessionUtil

pom.xml

<?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.powernode</groupId><artifactId>mybatis-008-select</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><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>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency></dependencies><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>

mybatis-config

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="jdbc.properties"/><typeAliases><package name="com.powernode.mybatis.pojo"/></typeAliases><environments default="dev"><environment id="dev"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><package name="com.powernode.mybatis.mapper"/></mappers>
</configuration>

logback

<?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} [%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>

jdbc.properties

<?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} [%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>

CarMapper

package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;/* @author wuw* @since 2023-04-11 10:13:56*/
public interface CarMapper {}

Car

package com.powernode.mybatis.pojo;/* @author wuw* @since 2023-02-01 15:16:01*/
public class Car {//数据库表中的字段应该和pojo类的属性一一对应private Long id;private String carNum;private String brand;private Double guidePrice;private String produceTime;private String carType;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 Car(){}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;}@Overridepublic String toString() {return "car{" +"id=" + id +", carNum='" + carNum + '\\'' +", brand='" + brand + '\\'' +", guidePrice=" + guidePrice +", produceTime='" + produceTime + '\\'' +", carType='" + carType + '\\'' +'}';}
}

SqlSessionUtil

package com.powernode.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;/* @author wuw* @since 2023-04-04 09:42:28*/
public class SqlSessionUtil {private static SqlSessionFactory sqlSessionFactory;/* 类加载时初始化sqlSessionFactory对象*/static {try {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));} catch (Exception e) {e.printStackTrace();}}private static ThreadLocal<SqlSession> local = new ThreadLocal<>();/* 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。 @return 新的会话对象*/public static SqlSession openSession() {SqlSession sqlSession = local.get();if (sqlSession == null) {sqlSession = sqlSessionFactory.openSession();local.set(sqlSession);}return sqlSession;}/* 关闭SqlSession对象* @param sqlSession*/public static void close(SqlSession sqlSession){if (sqlSession != null) {sqlSession.close();}local.remove();}
}

CarMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.powernode.mybatis.mapper.CarMapper"></mapper>

一、返回Car

当查询的结果,有对应的实体类,并且查询结果只有一条时:

第一步、CarMapper接口

package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;/* @author wuw* @since 2023-04-11 10:13:56*/
public interface CarMapper {/* 根据Id查Car信息* @param Id* @return*/Car selectById(Long Id);
}

第二步、CarMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.powernode.mybatis.mapper.CarMapper"><select id="selectById" resultType="Car">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}</select>
</mapper>

第三步、运行测试类

package com.powernode.mybatis.test;import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.junit.Test;public class CarMapperTest {@Testpublic void testSelectById(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);Car car = mapper.selectById(10L);System.out.println(car);}
}

第四步、执行结果

 查询结果是一条的话可以使用List集合接收吗?当然可以

第一步、CarMapper接口

/
* 根据id主键查询:结果最多只有一条,可以放到List集合中吗?
* @return
*/
List<Car> selectByIdToList(Long id);

第二步、CarMapper.xml

<select id="selectByIdToList" resultType="Car">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
</select>

第三步、运行测试类

@Test
public void testSelectByIdToList(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);List<Car> cars = mapper.selectByIdToList(9L);System.out.println(cars);
}

第四步、执行结果

二、返回List<Car>

当查询的记录条数是多条的时候,必须使用集合接收。如果使用单个实体类接收会出现异常。

第一步、CarMapper接口

/
* 查询所有的Car
* @return
*/
List<Car> selectAll();

第二步、CarMapper.xml

<select id="selectAll" resultType="Car">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>

第三步、运行测试类方法

@Test
public void testSelectAll(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);List<Car> cars = mapper.selectAll();cars.forEach(car -> System.out.println(car));
}

第四步、查看执行结果

如果返回多条记录,采用单个实体类接收会怎样?

第一步、CarMapper接口

/
* 查询多条记录,采用单个实体类接收会怎样?
* @return
*/
Car selectAll2();

第二步、CarMapper.xml

<select id="selectAll2" resultType="Car">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>

第三步、运行测试类方法

@Test
public void testSelectAll2(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);Car car = mapper.selectAll2();System.out.println(car);
}

第四步、查看执行结果

三、返回Map

当返回的数据,没有合适的实体类对应的话,可以采用Map集合接收。字段名做key,字段值做value。

查询如果可以保证只有一条数据,则返回一个Map集合即可。

 第一步、CarMapper接口

/* 通过id查询一条记录,返回Map集合* @param id* @return*/
Map<String, Object> selectByIdRetMap(Long id);

第二步、CarMapper.xml

<select id="selectByIdRetMap" resultType="map">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
</select>

resultMap="map",这是因为mybatis内置了很多别名。【参见mybatis开发手册】

第三步、运行测试类方法

@Test
public void testSelectByIdRetMap(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);Map<String,Object> car = mapper.selectByIdRetMap(31L);System.out.println(car);
}

第四步、查看执行结果

 

当然,如果返回一个Map集合,可以将Map集合放到List集合中吗?当然可以,这里就不再测试了。

反过来,如果返回的不是一条记录,是多条记录的话,只采用单个Map集合接收,这样同样会出现之前的异常:TooManyResultsException

四、List<Map>

查询结果条数大于等于1条数据,则可以返回一个存储Map集合的List集合。List<Map>等同于List<Car>

第一步、CarMapper接口

/* 查询所有的Car,返回一个List集合。List集合中存储的是Map集合。* @return*/
List<Map<String,Object>> selectAllRetListMap();

第二步、CarMapper.xml

<select id="selectAllRetListMap" resultType="map">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>

第三步、运行测试类方法

@Test
public void testSelectAllRetListMap(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);List<Map<String,Object>> cars = mapper.selectAllRetListMap();System.out.println(cars);
}

第四步、 查看执行结果

 

 五、返回Map<String,Map>

拿Car的id做key,以后取出对应的Map集合时更方便

第一步、CarMapper接口

/* 获取所有的Car,返回一个Map集合。* Map集合的key是Car的id。* Map集合的value是对应Car。* @return*/
@MapKey("id")
Map<Long,Map<String,Object>> selectAllRetMap();

第二步、CarMapper.xml

<select id="selectAllRetMap" resultType="map">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>

第三步、运行测试类方法

@Test
public void testSelectAllRetMap(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);Map<Long,Map<String,Object>> cars = mapper.selectAllRetMap();System.out.println(cars);
}

第四步、 查看执行结果

 

六、resultMap结果映射

查询结果的列名和java对象的属性名对应不上怎么办?

  • 第一种方式:as 给列起别名
  • 第二种方式:使用resultMap进行结果映射
  • 第三种方式:是否开启驼峰命名自动映射(配置settings)

之前用的第一种方式,现在介绍一下第二和第三种方式

使用resultMap进行结果映射

第一步、CarMapper接口

/* 查询所有Car,使用resultMap进行结果映射* @return*/
List<Car> selectAllByResultMap();

第二步、CarMapper.xml

<!--resultMap:id:这个结果映射的标识,作为select标签的resultMap属性的值。type:结果集要映射的类。可以使用别名。
-->
<resultMap id="carResultMap" type="car"><!--对象的唯一标识,官方解释是:为了提高mybatis的性能。建议写上。--><id property="id" column="id"/><result property="carNum" column="car_num"/><!--当属性名和数据库列名一致时,可以省略。但建议都写上。--><!--javaType用来指定属性类型。jdbcType用来指定列类型。一般可以省略。--><result property="brand" column="brand" javaType="string" jdbcType="VARCHAR"/><result property="guidePrice" column="guide_price"/><result property="produceTime" column="produce_time"/><result property="carType" column="car_type"/>
</resultMap><!--resultMap属性的值必须和resultMap标签中id属性值一致。-->
<select id="selectAllByResultMap" resultMap="carResultMap">select * from t_car
</select>

第三步、运行测试类方法

@Test
public void testSelectAllByResultMap(){CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);List<Car> cars = carMapper.selectAllByResultMap();System.out.println(cars);
}

第四步、查看执行结果

执行结果正常。 

是否开启驼峰命名自动映射

使用这种方式的前提是:属性名遵循Java的命名规范,数据库表的列名遵循SQL的命名规范。

Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。

SQL命名规范:全部小写,单词之间采用下划线分割。

比如以下的对应关系:

实体类中的属性名

数据库表的列名

carNum

car_num

carType

car_type

produceTime

produce_time

 如何启用该功能,在mybatis-config.xml文件中进行配置:

<!--放在properties标签后面-->
<settings><setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

第一步、CarMapper接口

/
* 查询所有Car,启用驼峰命名自动映射
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();

第二步、CarMapper.xml配置文件

<select id="selectAllByMapUnderscoreToCamelCase" resultType="Car">select * from t_car
</select>

第三步、运行测试类方法

@Test
public void testSelectAllByMapUnderscoreToCamelCase(){CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);List<Car> cars = carMapper.selectAllByMapUnderscoreToCamelCase();System.out.println(cars);
}

第四步、查看执行结果

执行结果正常。 

七、返回总记录条数

需求:查询总记录条数

第一步、CarMapper接口

/* 获取总记录条数* @return*/
Long selectTotal();

第二步、carMapper.xml

<!--long是别名,可参考mybatis开发手册。-->
<select id="selectTotal" resultType="long">select count(*) from t_car
</select>

第三步、运行测试类方法

@Test
public void testSelectTotal(){CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);Long total = carMapper.selectTotal();System.out.println(total);
}

第四步、查看执行结果