MyBatis-XxxxMapper.xml-SQL 映射文件
MyBatis-XxxxMapper.xml-SQL 映射文件
1.官方文档
1.文档地址
https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
2.XxxMapper.xml-基本介绍
1、MyBatis 的真正强大在于它的语句映射(在 XxxMapper.xml 配置), 由于它的异常强大, 如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。 MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
2、SQL 映射文件常用的几个顶级元素(按照应被定义的顺序列出)
cache – 该命名空间的缓存配置。
cache-ref – 引用其它命名空间的缓存配置。
resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
parameterType - 将会传入这条语句的参数的类全限定名或别名
sql – 可被其它语句引用的可重用语句块。
insert – 映射插入语句。
update – 映射更新语句。
delete – 映射删除语句。
select – 映射查询语句。
3.XxxMapper.xml-详细说明
1.新建 Module xml-mapper
1、在原来的项目中,新建 xml-mapper 项目演示 xml 映射器的使用
2、新建 Module 后,先创建需要的包,再将需要的文件/资源拷贝过来(这里我们拷贝 Monster.java、resources/jdbc.properties 和 mybatis-config.xml)
3、创建 MonsterMapper.java MonsterMapper.xml 和 MonsterMapperTest.java
2.基本使用
- insert、delete、update、select 分别对应增删改查的方法和 SQL 语句的映射.
- 如何获取到刚刚添加的 Monster 对象的 id 主键
<!--配置save
1. id="save" 就是接口的方法名
2. parameterType="com.llp.entity.Monster" 放入的形参的类型
3. 注意"com.llp.entity.Monster" 可以简写
4. 写入sql语句=> 现在sqlyog 写完成-测试通过,再拿过来
5. (`age`, `birthday`, `email`, `gender`, `name`, `salary`) 表的字段
6. (#{age}, #{birthday}, #{email}, #{gender}, #{name}, #{salary}) 是从传入的monster对象属性值
7. 这里 #{age} age 对应monster对象的属性名,其它一样
-->
<insert id="save" parameterType="com.llp.entity.Monster" useGeneratedKeys="true" keyProperty="id">
INSERT INTO `monster`
(`age`, `birthday`, `email`, `gender`, `name`, `salary`)
VALUES (#{age}, #{birthday}, #{email}, #{gender}, #{name}, #{salary})
</insert>
3. parameterType(输入参数类型)
● parameterType(输入参数类型)
- 传入简单类型,比如按照 id 查 Monster(前讲过)
- 传入 POJO 类型,查询时需要有多个筛选条件
- 当有多个条件时,传入的参数就是 Pojo 类型的 Java 对象,比如这里的 Monster 对象
- 当传入的参数类是 String 时,也可以使用 ${} 来接收参数
● parameterType-应用案例
案例 1:请查询 id = 1 或者 name = '牛魔王' 的妖怪
案例 2:请查询 name 中 包含 "牛魔王" 的妖怪
1.修改 MonsterMapper.java, 增加方法接口
public interface MonsterMapper {
//通过 id 或者名字查询
List<Monster> findMonsterByNameORId(Monster monster);
// 查询名字中含义'精'妖怪
List<Monster> findMonsterByName(@Param("name") String name);
}
- 修改 MonsterMapper.xml
<!--配置别名-->
<!--<typeAliases>-->
<!--<typeAlias type="com.llp.entity.Monster" alias="Monster"/>-->
<!--
如果一个包下有很多的类,我们可以直接引入包,这样
该包下面的所有类名,可以直接使用
-->
<!--<package name="com.llp.entity"/>-->
<!--</typeAliases>-->
<!--我们在mybatis-config.xml中配置了别名包扫描,resultType也可以直接写实体 resultType=Monster -->
<select id="findMonsterByNameORId" resultType="com.llp.entity.Monster">
select * from monster where name=#{name} or id = #{id}
</select>
<!--
这里我们如果使用like '%#{name}%'的方式会抛出类似下面的异常
Cause: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
1.糊查询的使用 取值 需要 ${value} 或者 CONCAT('%', #{value}, '%') 的方式
2.MyBatis中sql用双引号和单引号都是可以,建议使用单引号 like ""%${name}%"
-->
<select id="findMonsterByName" resultType="com.llp.entity.Monster">
select * from monster where name like '%${name}%'
</select>
- 修改 MonsterMapperTest.java ,完成测试
@Test
public void findMonsterByNameORId(){
Monster monster = new Monster();
monster.setName("牛魔王");
monster.setId(1);
List<Monster> monsterList = monsterMapper.findMonsterByNameORId(monster);
for (Monster m : monsterList) {
System.out.println(m);
}
}
@Test
public void findMonsterByName(){
List<Monster> monsterList = monsterMapper.findMonsterByName("牛魔王");
for (Monster monster : monsterList) {
System.out.println(monster);
}
}
4.传入 HashMap
● 传入 HashMap(重点)
- HashMap 传入参数更加灵活,比如可以灵活的增加查询的属性,而不受限于 Monster 这 个 Pojo 属性本身
- 演示如何遍历一个 List<Map<String,Object>> 的数据类型
● 传入 HashMap- 应用实例
要求:声明一个方法,按传入参数是 HashMap 的方式,查询 id >=1 并且 salary 大于 40 的所有妖怪
- 修改 MonsterMapper.java
//查询 id >= 1 并且 salary 大于 40, 要求传入的参数是 HashMap
List<Monster> findMonsterByMap(Map<String, Object> map);
2.修改 MonsterMapper.xml
<!--查询 id >= 1 并且 salary 大于 40, 要求传入的参数是 HashMap
注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
-->
<select id="findMonsterByMap" resultType="com.llp.entity.Monster">
select * from monster where id>= #{id} and salary > #{salary}
</select>
- 修改 MonsterMapperTest.java
@Test
public void findMonsterByMap(){
Map<String,Object> map = new HashMap<>();
// 注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
map.put("id",1);
map.put("salary",40);
List<Monster> monsterList = monsterMapper.findMonsterByMap(map);
for (Monster monster : monsterList) {
System.out.println(monster);
}
}
● 传入和返回 HashMap- 应用实例
1.修改 MonsterMapper.java
//查询 id >=1 并且 salary 大于 40, 要求传入的参数是 HashMap 返回的也是Map
List<Map<String, Object>> findMonsterByMapAndReturnMap(Map<String, Object> map);
2.修改 MonsterMapper.xml
<!--查询 id >= 1 并且 salary 大于 40, 要求传入的参数是 HashMap
注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
-->
<select id="findMonsterByMapAndReturnMap" resultType="java.util.Map">
SELECT id,name FROM monster WHERE id >= #{id} AND salary > #{salary}
</select>
3.测试
@Test
public void findMonsterByMapAndReturnMap(){
Map<String,Object> map = new HashMap<>();
// 注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
map.put("id",1);
map.put("salary",40);
List<Map<String, Object>> mapList = monsterMapper.findMonsterByMapAndReturnMap(map);
for (Map<String, Object> monsterMap : mapList) {
System.out.println(monsterMap);
//遍历monsterMap去除属性和值
for (String key : monsterMap.keySet()) {
System.out.println(key+"="+monsterMap.get(key));
}
for (Map.Entry<String, Object> entry : monsterMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
}
}
}
5.resultMap(结果集映射)
1.应用实例
● 基本介绍
当实体类的属性和表的字段名字不一致时,我们可以通过 resultMap 进行映射,从而屏蔽 实体类属性名和表的字段名的不同.
● 案例演示
- 创建表 user
-- 创建的 user 表
CREATE TABLE `user` (
`user_id` INT NOT NULL AUTO_INCREMENT,
`user_email` VARCHAR ( 255 ) DEFAULT '',
`user_name` VARCHAR ( 255 ) DEFAULT '',
PRIMARY KEY ( `user_id` )
) CHARSET = utf8
2.创建src\main\java\com\llp\entity\User.java,这里我们故意的不适用标准的小驼峰方式,让实体和数据库字段不匹配
@Data
public class User {
private Integer user_id;
private String username;
private String useremail;
}
3.创建src\main\java\com\llp\mapper\UserMapper.java
public interface UserMapper {
//添加方法
void addUser(User user);
//查询所有的 User
List<User> findAllUser();
}
4.创建src\main\java\com\llp\mapper\UserMapper.xml
<mapper namespace="com.llp.mapper.UserMapper">
<!--
1、配置方法public void addUser(User user);
2、完成添加用户的任务, 注意这里user属性和表的字段名不一致
-->
<insert id="addUser" parameterType="User">
INSERT INTO `user` (`user_email`,`user_name`)
VALUE (#{useremail}, #{username})
</insert>
<!--
1. 配置方法public List<User> findAllUser();
2. 返回所有的user信息
3. 按照传统的方式完成,会出现什么问题?=> 如果对象属性名和表字段相同时,就会设置值, 如果不同, 就会是默认值
4. 我们可以使用resultMap来解决
5. resultMap : 表示我们要定义一个resultMap
6. id="findAllUserMap" => id 就是程序员指定的resultMap id ,后面通过id可以使用他
7. type="User" , 就是你需要返回的对象类型
8. result column="user_email" property="useremail": column="user_email" 表的字段名, property="useremail" 对象属性名
9. resultMap="findAllUserMap" 表示使用我们定义的 resultMap , 通过id关联
-->
<resultMap id="findAllUserMap" type="User">
<result column="user_email" property="useremail"/>
<result column="user_name" property="username"/>
</resultMap>
<select id="findAllUser" resultMap="findAllUserMap">
SELECT * FROM `user`
</select>
<!--使用表字段别名,来解决表的字段名和对象属性名,不一致问题, 可以用,但是我们仍然推荐使用resultmap-->
<!--<select id="findAllUser" resultType="User">-->
<!-- SELECT user_id ,user_name AS username,user_email AS useremail FROM `user`-->
<!--</select>-->
</mapper>
5.创建src\test\java\com\llp\mapper\UserMapperTest.java
public class UserMapperTest {
private SqlSession sqlSession;
private UserMapper userMapper;
/**
* 当方法标注 @Before, 表示在执行你的目标测试方法前,会先执行该方法
*/
//编写方法完成初始化
@Before
public void init() {
this.sqlSession = MyBatisUtil.getSqlSession();
userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println(sqlSession);
}
@Test
public void saveUser(){
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUser_id(i);
user.setUseremail("123@qq.com");
user.setUsername("wukong");
userMapper.addUser(user);
//新增、删除、修改 mybatis默认开启事务需要手动提交
if(sqlSession !=null){
sqlSession.commit();
}
}
}
@Test
public void findAllUser(){
List<User> allUser = userMapper.findAllUser();
for (User user : allUser) {
System.out.println(user);
}
}
/**
* 当方法标注 @After, 表示在执行你的目标测试方法后,会先执行该方法
*/
@After
public void close() {
if (sqlSession != null) {
//Returned connection 1412925683 to pool.
sqlSession.close();
}
}
}
测试结果
2.注意事项和细节
1、解决表字段和对象属性名不一致, 也支持使用字段别名
<!-- 实现 findAllUser【使用别名 屏蔽属性名和字段名不一致 可以用,但是复用性不 ok 】 -->
<select id="findAllUser" resultType="User"> SELECT user_id,user_name AS username, user_email AS useremail FROM user </select>
2、说明:如果是 MyBatis-Plus 处理就比较简单, 可以使用 注解@TableField 来解决 实体字段名和表字段名不一致的问题,还可以使用@TableName 来解决 实体类名和表名 不一致的问题
标题:MyBatis-XxxxMapper.xml-SQL 映射文件
作者:llp
地址:https://llinp.cn/articles/2022/07/03/1656845842511.html