这里写目录标题
一级目录
二级目录
三级目录
目标
- 能够了解什么是框架
- 掌握Mybatis框架开发快速入门
- 掌握Mybatis框架的基本CRUD操作
- 掌握SqlMapConfig.xml配置文件
- 掌握Mybatis的parameterType的配置
- 掌握Mybatis的resultType的配置
- 了解Mybatis连接池与事务操作
- 掌握Mybatis动态SQL
1 jdbc 问题分析
- 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
- Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大, sql 变动需要改变java 代码。
- 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
- 对结果集解析存在硬编码(查询列名), sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便
2 MyBatis框架概述
mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过xml 或注解的方式将要执行的各种statement 配置起来,并通过java 对象和statement 中sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql并将结果映射为 java 对象并返回。
采用 ORM 思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与 jdbc api打交道,就可以完成对数据库的持久化操作。
官网: http://www.mybatis.org/mybatis-3/
小结
- MyBatis: 持久层的一个框架, 封装了JDBC. 操作数据库
- 为什么要学习MyBatis?
- JDBC和DBUtils都有一些很明显的缺点, JDBC和DBUtils不适合做项目
- MyBatis是工作里面的主流的持久层框架, 使用几率特别大
1.需求
- 使用MyBatis查询所有的用户, 封装到List集合
2.分析
- 创建Maven工程(jar), 添加坐标
- 创建pojo
- 创建UserDao接口
- 创建UserDao映射文件
- 创建MyBatis核心配置文件SqlMapConfig.xml
- 编写java代码测试
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--引入lombok的依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
</dependencies>
1.2 创建 UserDao 接口
- UserDao 接口就是我们的持久层接口(也可以写成 UserMapper) .我们就写成UserDao ,具体代码如下:
public interface UserDao {
public List<User> findAll();
}
1.3 创建 UserDao.xml 映射文件
注意:
- 映射配置文件存储的路径在resources里面,要和对应的Dao接口的路径保持一致
- 映射配置文件的文件名必须和Dao接口名保持一致
- 一定要引入约束文件
mapper.xml格式如下
1.mapper文件的文件名和dao的名字一样,存放在resources下面的时候前文件名最好一致。mapper也可直接在src下面存放,和dao文件存放挨着,但不建议那样子做。2.resources下面是文件夹的形式,是以/为开始的,不是以.
<?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,一个映射配置文件,就对应一个dao接口
根标签的namespace属性的值就对应dao接口的全限定名
-->
<mapper namespace="com.weijisheng.dao.UserDao">
<!--
根标签的每一个子标签就对应dao接口的每一个方法:
select标签就对应查询方法
标签的id的值对应方法的名字
标签的resultType的值就对应封装结果的类型,如果封装结果的类型是List就对应其泛型的类型
标签体的内容就是要执行的SQL语句
-->
<select id="findAll" resultType="com.weijisheng.dao.UserDao">
select * from t_user
</select>
</mapper>
#####1.4.创建 SqlMapConfig.xml 配置文件(核心配置文件)
注意事项
- 存放路径必须是resources的根路径
- 配置文件的名字,随便写
- 一定要引入约束文件
<?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
-->
<configuration>
<!--
配置数据库的环境信息:
environments: 表示里面可以配置多个环境,default表示使用哪个环境
environment: 每一个environment表示一种环境
为什么要配置多个环境: 因为我们有多个环境(开发环境、生产环境(真正项目之后运行的环境)、测试环境)
-->
<environments default="dev">
<!--开发环境-->
<environment id="dev">
<!--
事务管理者,type为JDBC表示使用JDBC的事务管理者(了解)
-->
<transactionManager type="JDBC"></transactionManager>
<!--
dataSource表示数据源,1. POOLED表示使用自带连接池 2. UNPOOLED表示不使用连接池 3. JNDI表示使用JNDI的连接池
-->
<dataSource type="POOLED">
<!--连接池的配置信息-->
<property name="username" value="root"/>
<property name="password" value=""/>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value=""/>
</dataSource>
</environment>
<!--生产环境-->
<environment id="pro">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
<!--测试环境-->
<environment id="test">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!--
指定加载哪些映射配置文件: mappers
mapper标签: 每一个mapper标签负责加载一个映射配置文件;resource指定要加载的映射配置文件的路径
-->
<mappers>
<mapper resource="com/weijisheng/dao/UserDao.xml"></mapper>
</mappers>
</configuration>
1.5测试
package com.weijisheng;
import com.weijisheng.dao.UserDao;
import com.weijisheng.pojo.User;
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 org.junit.Test;
import java.io.IOException;
import java.util.List;
import java.io.InputStream;
public class TestMybatis {
public class TestMybatis {
@Test
public void testFindAll() throws Exception {
//1. 让mybatis框架去加载主配置文件
//1.1 将主配置文件SqlMapConfig.xml转换成字节输入流
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//1.2 创建一个SqlSessionFactoryBuilder
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
//1.3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = factoryBuilder.build(is); //使用了构建者模式
//1.4 使用sessionFactory对象创建出sqlSession对象
SqlSession sqlSession = sessionFactory.openSession(); //使用了工厂模式
//2. 使用sqlSession对象创建出UserDao接口的代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class); //使用了动态代理
//3. 调用userDao代理对象的findAll()方法进行查询
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
//4. 关闭资源
sqlSession.close();
is.close();
}
小结
步骤
1. 创建maven工程(javase)
2. 引入依赖:mysql、mybatis、Junit、lombok
3. 创建POJO类、创建Dao接口
4. 创建Dao接口对应的映射配置文件
1. 路径要在resources里面和Dao接口的路径一致,而且在resources目录中创建目录的时候要使用"/"而不是"."
2. 映射配置文件的文件名要和对应的Dao接口的名字一致
5. 创建mybatis的核心配置文件
6. 编写mybatis的测试代码进行测试
properties(引入外部properties文件)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
3.2.properties
- jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=
jdbc.user=root
jdbc.password=
- 引入到核心配置文件
<configuration>
<properties resource="jdbc.properties">
</properties>
<!--数据源配置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="UNPOOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
....
</configuration>
3.3.typeAliases(类型别名)
3.3.1定义单个别名
- 核心配置文件
<typeAliases>
<typeAlias type="com.weijisheng.bean.User" alias="user"></typeAlias>
</typeAliases>
- 修改UserDao.xml
<select id="findAll" resultType="user">
SELECT * FROM user
</select>
3.3.2批量定义别名
使用package定义的别名:就是pojo的类名,大小写都可以
- 核心配置文件
<typeAliases>
<package name="com.weijisheng.bean"/>
</typeAliases>
- 修改UserDao.xml
<select id="findAll" resultType="user">
SELECT * FROM user
</select>
3.4.Mapper
3.4.1方式一:引入映射文件路径
<mappers>
<mapper resource="com/weijisheng/dao/UserDao.xml"/>
</mappers>
3.4.2方式二:扫描接口
- 配置单个接口
<mappers>
<mapper class="com.weijisheng.dao.UserDao"></mapper>
</mappers>
- 批量配置
<mappers>
<package name="com.weijisheng.dao"></package>
</mappers>
4.小结
-
核心配置文件的顺序
-
properties 引入properties文件的
- 创建properties文件
- 使用
<properties resource="文件的路径"/>
- 使用 ${key}
-
typeAliases(类型别名) 在Dao映射文件里面 直接写类(pojo)的名字, 不需要写类全限定名了
<typeAliases>
<package name="com.weijisheng.bean"/>
</typeAliases>
- Mapper 引入Dao映射文件的
<mappers>
<package name="com.weijisheng.dao"></package>
</mappers>
MyBatis进阶
知识点-日志的使用(会用)
1.目标
我们在使用MyBatis的时候, 其实MyBatis框架会打印一些必要的日志信息, 在开发阶段这些日志信息对我们分析问题,理解代码的执行是特别有帮助的; 包括项目上线之后,我们也可以收集项目的错误日志到文件里面去; 所有我们采用专门的日志系统来处理.
2.步骤
- 导入坐标
- 拷贝日志配置文件到项目
3.讲解
- 导入坐标
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
<!-- log end -->
- 拷贝log4j.properties到resources目录
log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#[%-5p] %t %l %d %rms:%m%n
#%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %t %l %d %rms:%m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\idea_project\\wei_mm_backend.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n
级别:error > warn > info>debug>trace
mybatis之增删改查
注意:除了select均没有resultType
目录结构
1.增加联系人
- UserDao中添加新增方法
public interface UserDao {
/**
* 添加用户
* @param user 要添加进数据库的数据
* @return 受到影响的行数
*/
int addUser(User user);
}
- 在 UserDao.xml 文件中加入新增配置
<insert id="insertUser" parameterType="User">
insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>
<!--我们可以发现, 这个 sql 语句中使用#{}字符, #{}代表占位符,我们可以理解是原来 jdbc 部分所学的?,它们都是代表占位符, 具体的值是由 User 类的 username 属性来决定的。
parameterType 属性:代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的
全名称。-->
- 添加测试类中的测试方法
public class TestMybatis {
private UserDao userDao;
private SqlSession sqlSession;
private InputStream is;
@Before
public void init() throws Exception {
//1. 让mybatis框架去加载主配置文件
//1.1 将主配置文件SqlMapConfig.xml转换成字节输入流
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//1.2 创建一个SqlSessionFactoryBuilder
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
//1.3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = factoryBuilder.build(is); //使用了构建者模式
//1.4 使用sessionFactory对象创建出sqlSession对象
//使用了工厂模式
sqlSession = sessionFactory.openSession();
//2. 使用sqlSession对象创建出UserDao接口的代理对象
//使用了动态代理
userDao = sqlSession.getMapper(UserDao.class);
}
@Test
public void testinsert() throws IOException, ParseException {
String date="1997-04-02";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date parse = dateFormat.parse(date);
User user = new User(null,"王菲","女",parse,"地球");
int insertUser = mapper.insertUser(user);
//重点获取uid,详情见如下mapper.xml文件
System.out.println(user.getUid());
System.out.println(insertUser);
}
@After
public void destroy() throws IOException {
//提交事务
sqlSession.commit();
//4. 关闭资源
sqlSession.close();
is.close();
}
}
2 新增用户 id 的返回值
新增用户后, 同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。
- SelectKey获取主键
属性 | 描述 |
---|---|
keyProperty | selectKey 语句结果应该被设置的目标属性。 |
resultType | 结果的类型。MyBatis 通常可以算出来,但是写上也没有问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。 |
order | 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用。 |
UserDao.xml
<!--
resultType只有select标签才有
我们需要在标签体的SQL语句中,获取pojo类型的参数的属性: #{属性名}
selectKey标签: 查询主键
keyColumn 表示要查询的列名
keyProperty 表示要赋值的属性名
resultType 表示查询出来的结果的类型
order 表示在前或者在后执行
select last_insert_id() 查询最后一个自增长的id的值
-->
<insert id="insertUser" parameterType="User">
<selectKey resultType="int" order="AFTER" keyProperty="uid" keyColumn="uid">
select last_insert_id()
</selectKey>
insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>
3 模糊查询的写法
- UserDao 中添加新增方法
/**
* 根据用户名进行模糊查询
*/
List<User> searchByUsername(String username);
- 在 UserMapper.xml 文件中加入新增配置
<select id="searchByUsername" resultType="User" parameterType="String">
select * from t_user where username like "%"#{username}"%"
</select>
concat是mybatis中连接字符串的,所以上述语句可以写成
select *from t_user where username like concat("%",#{username},"%");
还有一种是${}的,代码如下:
select * from t_user where username like '%${value}%'
#{}与${}的区别【面试】
- #{}一定不能写在引号里面,${}一定要写在引号里面
- 如果是pojo、map类型的参数,无论是#{}还是${}里面都是些属性名
- 如果是简单类型的参数,#{}里面可以写任意字符串,但是${}里面只能写value(以前的版本)
- 如果使用#{}引入参数的话,其实是先使用?占位符,然后再设置参数;而使用${}引入参数的话,是直接拼接SQL语句
mybatis工具类的封装
SqlSessionFactoryUtil.java
package com.weijisheng.util;
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;
import java.io.InputStream;
public class SqlSessionFactoryUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//1 将主配置文件SqlMapConfig.xml转换成字节输入流
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2 创建一个SqlSessionFactoryBuilder
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
//3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
sqlSessionFactory = factoryBuilder.build(is); //使用了构建者模式
System.out.println(sqlSessionFactory);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建SqlSession对象
* @return
*/
public static SqlSession openSqlSession(){
System.out.println(sqlSessionFactory.openSession());
return sqlSessionFactory.openSession();
}
/**
* 提交事务并且关闭sqlSession
* @param sqlSession
*/
public static void commitAndClose(SqlSession sqlSession){
sqlSession.commit();
sqlSession.close();
}
/**
* 回滚事务并且关闭sqlSession
* @param sqlSession
*/
public static void rollbackAndClose(SqlSession sqlSession){
sqlSession.rollback();
sqlSession.close();
}
}
mybatis的映射配置文件的parameterType参数类型(important):
-
单个参数,方法就以简单类型传入即可,那么在映射配置文件中的parameterType的值就是这个简单类型的别名
在SQL语句中引入简单类型的参数#{任意字符串} -
多个参数:
-
传入多个简单类型的参数(不太提倡)我们需要通过Param注解给每个参数取名,那么在映射配置文件中就不写parameterType
在SQL语句中引入参数#{Param注解的值} -
将多个参数封装到一个POJO中,那么在映射配置文件中parameterType的值就是这个POJO的全限定名或者别名
在SQL语句中引入参数#{POJO的属性名}或者’${POJO的属性名}’ -
将多个参数封装到一个Map中(要封装的参数没有对应的POJO),那么在映射配置文件中parameterType的值是map,
在SQL语句中引入参数#{map的key}或者’${map的key}’ -
将多个参数封装到一个POJO的包装对象中
什么是POJO的包装对象,也就是说POJO中的属性类型又是一个其他的POJO类型, 那么我们在映射配置文件中的parameterType的值就是包装类型的别名
在SQL语句中引入参数#{属性名.属性名}
第四个代码演示如下:
QueryVo.java
package com.weijisheng.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author weijisheng
* @create 2021-12-04 18:32
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryVo {
/**
* 不需要最后一个属性做参数
* @param currentPage
* @param pageSize
* @param queryCondition
*/
public QueryVo(Long currentPage, Integer pageSize, User queryCondition) {
this.currentPage = currentPage;
this.pageSize = pageSize;
this.queryCondition = queryCondition;
}
private Long currentPage;
private Integer pageSize;
/**
* 查询条件,多个pojo
*/
private User queryCondition;
private Long offset;
/**
* 下面这个是为了limit的第一个参数,要跳过的。
* @return
*/
public Long getOffset() {
return (currentPage - 1)*pageSize;
}
}
UserDao.java
package com.weijisheng.dao;
import com.weijisheng.pojo.QueryVo;
import com.weijisheng.pojo.User;
import java.util.List;
/**
* @author weijisheng
* @create 2021-12-04 18:09
*/
public interface UserDao {
List<User> findAll();
/**
* 传入pojo
* @param queryVo
* @return
*/
List<User> findPage(QueryVo queryVo);
}
UserDao.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">
<mapper namespace="com.weijisheng.dao.UserDao">
<select id="findAll" resultType="User">
select *from t_user;
</select>
<select id="findPage" parameterType="QueryVo" resultType="User">
select *from t_user where sex=#{queryCondition.sex} and address=#{queryCondition.address}
limit #{offset},#{pageSize}
</select>
</mapper>
Test.java
@Test
public void findPage(){
SqlSession sqlSession = SqlFactoryUtils.openSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = new User();
user.setSex("女");
user.setAddress("武汉");
QueryVo queryVo = new QueryVo(1l, 3, user);
List<User> page = mapper.findPage(queryVo);
for (User u :
page) {
System.out.println(u);
}
SqlFactoryUtils.commitAndClose(sqlSession);
}
mybatis的映射配置文件的参数结果类型的深入(important):
1. 输出简单类型
2. 输出pojo对象
3. 输出pojo列表
4. resultMap结果类型
3.1输出简单类型
查询的结果是单个数据, 映射配置文件中的resultType属性的值就是这个数据的类型
/**
* 查询用户的总个数
* @return
*/
Long findTotal();
<select id="findTotal" resultType="long">
select count(*) from t_user
</select>
3.2输出pojo对象(一个pojo对象就对应一行数据)或者一个Map
查询的结果是一行数据:
- 将这一行数据存储到POJO对象中, 映射配置文件的resultType的值就是POJO的全限定名或者别名,此时就要求查询结果的字段名和类型 要和POJO的属性名和类型一致
- 将这一行数据存储到Map对象,映射配置文件的resultType的值就是map,那么此时查询结果中的字段名就是map的key,字段值就是map的value
/**
* 根据id查询一条数据
* @param id
* @return
*/
User findById(int id);
/**
* 根据用户名查询用户
* @param username
* @return
*/
Map findByUsername(String username);
<select id="findById" parameterType="int" resultType="User">
select * from t_user where uid=#{id}
</select>
<select id="findByUsername" parameterType="string" resultType="map">
select * from t_user where username=#{username}
</select>
3.3输出pojo列表(一个pojo列表就对应多行数据)或者Map的列表
查询的结果是多行数据:
-
将多条数据存储到List中,映射配置文件的resultType的值就是POJO的别名
-
将多条数据存储到List
3.4 resultMap结果类型
resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。 (详见第二段笔记)
那我们今天就来看返回的列名与实体类的属性不一致时的情况. 下次再接着研究复杂的封装(多表查询) , 将查询到的t_user表的信息封装到UserInfo对象中
- UserInfo.java
package com.weijisheng.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo implements Serializable {
private Integer userId;
private String username;
private String userSex;
private String userBirthday;
private String userAddress;
}
- UserDao.java
public interface UserDao {
/**
* 查询所有用户信息,封装到UserInfo对象
* @return
*/
List<UserInfo> findAllUserInfo();
}
- UserDao.xml
<!--
resultType属性会进行自动映射: 根据结果集的字段名和POJO的属性名的对应关系进行映射
resultMap属性: 结果集映射(手动映射),我们要先使用resultMap标签编写一个手动映射规则,然后使用这个映射规则
-->
<!--
id就是这个映射规则的唯一标识
type就是要进行手动映射的类型:UserInfo
autoMapping="true" 表示能自动映射的就会进行自动映射,不能自动映射的属性,才进行手动映射
-->
<resultMap id="userInfoMap" type="UserInfo" autoMapping="true">
<!--
id标签表示对主键进行映射
column属性是要进行映射的主键的字段名(列名)
property是要进行映射的POJO的属性名
-->
<id column="uid" property="userId"></id>
<!--
result标签就是对其它的非主键进行映射
-->
<result column="sex" property="userSex"></result>
<result column="birthday" property="userBirthday"></result>
<result column="address" property="userAddress"></result>
</resultMap>
<select id="findAllUserInfo" resultMap="userInfoMap">
select * from t_user
</select>
小结
- 输出简单类型 直接写
java类型名
eg: int - 输出pojo对象 直接写
pojo类型名
eg: User - 输出pojo列表类型 写
列表里面的泛型的类型
eg: List 写User - ResultMap
- 解决查询出来的结果的列名和javaBean属性不一致的请求
- 复杂的pojo复杂(明天讲)
Mybatis 映射文件的 SQL 深入 (important----->动态sql):
Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。
知识点-动态 SQL 之 if标签
1.目标
我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。
比如在 id 如果不为空时可以根据 id查询,如果 username 不为空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
2.讲解
- UserDao.java
package com.weijisheng.dao;
import com.weijisheng.pojo.QueryVo;
import com.weijisheng.pojo.User;
import com.weijisheng.pojo.UserInfo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @author weijisheng
* @create 2021-12-04 18:09
*/
public interface UserDao {
/**
* 查询所有用户,根据动态sql片段
* @return
*/
List<User> findUsers();
/**
* 根据用户地址和性别查询
* @param address
* @param sex
* @return
*/
List<User> findUserListByAddressAndSex(@Param("addr") String address, @Param("sex") String sex);
/**
* 根据id批量删除,类似于购物车那种
* @param ids
*/
void deleteByIds(List<Integer> ids);
}
- UserDao.xml
<!--
加入一个判断,判断传入的address是否为空,使用if标签进行判断,该标签中的test属性就编写判断条件
-->
<select id="findUserListByAddress" parameterType="string" resultType="User">
select * from t_user
<!--
加入一个判断,判断传入的address是否为空,使用if标签进行判断,该标签中的test属性就编写判断条件
-->
<if test="address != null">
where address=#{address}
</if>
</select>
<select id="findUserListByAddressAndSex" parameterType="User" resultType="User">
select * from t_user
where 1=1
<if test="address != null">
and address=#{address}
</if>
<if test="sex != null">
and sex=#{sex}
</if>
</select>
知识点-动态 SQL 之where标签
1.目标
为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。
2.讲解
修改 UserDao.xml 映射文件如下:
注意: 可以自动处理第一个 and
<select id="findUserListByAddressAndSex" parameterType="User" resultType="User">
<include refid="select_all"/>
<!--
where标签的作用:
1. 可以在条件之前添加where关键字
2. 可以去掉第一个条件前的and
-->
<where>
<if test="address != null">
and address=#{address}
</if>
<if test="sex != null">
and sex=#{sex}
</if>
</where>
</select>
3.小结
- where标签用在自己写sql语句的时候 where关键字不好处理的情况,代替where ‘1’ = ‘1’
- 可以自动处理第一个 and , 建议全部加上and
知识点-动态标签之foreach标签
1.目标
- 掌握foreach标签的使用
2.1需求
- 批量删除: 根据id的集合删除所有元素
2.2 LinkManDao代码
/**
* 批量删除
* @param ids
*/
void deleteByIds(List<Integer> ids);
2.3 LinkManDao映射配置文件
<delete id="deleteByIds" parameterType="int">
delete from t_user
<!--
将传入的集合中的数据遍历出来,放到()里面
使用foreach标签遍历
collection属性:要遍历的集合,如果要遍历的是一个List则写成list
item属性: 遍历出来的每一个元素
separator属性: 遍历出来的每一个元素之间的分隔符
index属性: 遍历出来的每一个元素的索引
open属性: 在遍历出来的第一个元素之前拼接字符串
close属性: 在遍历出来的最后一个元素之后拼接字符串
-->
<foreach collection="list" item="id" separator="," open="where uid in(" close=")">
#{id}
</foreach>
</delete>
知识点-动态标签之Sql片段
1.目标
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。我们先到 UserDao.xml 文件中使用标签,定义出公共部分.
2.讲解
- 使用sql标签抽取
<!--
使用sql标签将重复的sql语句部分封装起来
在需要使用这个sql片段的地方,就用include标签引入就行了
-->
<sql id="select_all">
select uid,username,sex,address,birthday from t_user
</sql>
- 使用include标签引入使用
<select id="findUserListByAddress" parameterType="string" resultType="User">
<include refid="select_all"/>
<!--
加入一个判断,判断传入的address是否为空,使用if标签进行判断,该标签中的test属性就编写判断条件
-->
<if test="address != null">
where address=#{address}
</if>
</select>
<select id="findUserListByAddressAndSex" parameterType="User" resultType="User">
<include refid="select_all"/>
<!--
where标签的作用:
1. 可以在条件之前添加where关键字
2. 可以去掉第一个条件前的and
-->
<where>
<if test="address != null">
and address=#{address}
</if>
<if test="sex != null">
and sex=#{sex}
</if>
</where>
</select>
3.小结
- sql标签可以把公共的sql语句进行抽取, 再使用include标签引入. 好处:好维护, 提示效率