1 Mybatis参数传递机制研究
1.1 入参只有一个的情况
参数只有一个的情况----变量名称可以随便写#{xxxx}接收。
//MybatisDemo
User user = userMapper.getUserById(4);
//UserMapper.java
User getUserById(int id);
取参数值格式:#{变量名称}
- #{} 解析传递进来的参数数据
- ${}对传递进来的参数原样拼接在SQL中
- #{} 是预编译处理,${}是字符串替换。
- 使⽤#{}可以有效的防⽌SQL注⼊,提⾼系统安全性。
UserMapper.xml
<!-- User getUserById(int id);
*parameterType="int"**参数类型(可以省略不写)
取参数值格式:#{变量名称}
一个参数的情况下,变量名称可以随意指定!
-->
<select id="getUserById" resultType="com.itheima.bean.User">
select * from tb_user where id = #{xzxx}
</select>
1.2 入参有多个的情况
多个参数我们必须为参数设置别名:@Param(名称)
在取入参值的时候,名称必须与别名一致!!
//MybatisDemo
User user = userMapper.login("zbj" , "change");
//UserMapper.java
User login(@Param("name") String loginName, @Param("passWord") String passWord);
UserMapper.xml
可以看到下面代码的参数都被替换成了别名。
<!--
User login(String loginName, String passWord);
二个参数的情况下,不可以随便书写参数名称,参数必须设置别名
-->
<select id="login" resultType="com.itheima.bean.User">
select * from tb_user where loginName = #{name} and passWord = #{passWord}
</select>
1.3 入参是对象的情况
对象参数的话,参数值本身存在字段名称,我们可以直接用字段名称取参数值即可(前提是取名的时候对象字段名称必须与数据库的字段名称一样,否则也会出错):
底层原理,实际上是调用对象的get方法取参数:
#{userName } = user.getUserName();
#{loginName} = user.getLoginName();
注意:开发中例如注册信息多半是用对象封装以后,传入到底层保存。
//MybatisDemo
User user = new User();
user.setCreateDate(new Date());
user.setLoginName("nvgw");
user.setUserName("朱琳");
user.setPassWord("tangtang");
int count = userMapper.save(user);
//UserMapper.java
int save(User user);
UserMapper.xml
我们可以看到,下面代码我们传入的参数直接就是按照对象的字段名称提取值传入数据库。
<!-- int save(User user);
入参是一个对象 :可以直接按照对象的字段名称提取值
原理是调用对象的get方法获取字段值:
#{loginName} = user.getLoginName():
#{userName}= user.getUserName():
-->
<insert id="save" >
INSERT INTO `tb_user` (
`loginName`,
`userName`,
`passWord`,
`create_date`
)
VALUES
(
#{loginName},
#{userName},
#{passWord},
#{createDate}
)
</insert>
1.4 入参是Map集合的情况
Map集合作为Mybatis的入参,参数本身的名称就是键名称,所以可以直接根据键名称提取参数值!
//MybatisDemo
Map<String , String> maps = new HashMap<>();
maps.put("loginName" , "zbj");
maps.put("pwd" , "change");
User user = userMapper.loginByMap(maps);
//UserMapper.java
User loginByMap(Map<String, String> maps);
UserMapper.xml
可以看到下面代码的参数就是参照Map集合的键名称的,比如maps.put(“pwd” , “change”)==>passWord = #{pwd}
<!--
User loginByMap(Map<String, String> maps);
参数是Map集合的情况:因为Map集合的参数是有键的,我们可以直接根据键名称获取参数值
-->
<select id="loginByMap" resultType="com.itheima.bean.User">
select * from tb_user where loginName = #{loginName} and passWord = #{pwd}
</select>
1.5 入参是对象,但是对象中存在复合对象的情况
先添加地址类Address。
public class Address {
private String name; // 名称
private String code; // 编号
//getter setter toString省略
}
然后再在User类里面添加复合对象。
private Address addr;
...getter/setter,toString
参数是复合类型:直接提取复合对象.内部字段
//MybatisDemo
User u = new User();
Address a = new Address();
a.setName("广州");
u.setAddr(a);
//UserMapper.java
List<User> getUsersByAddr(User u);
UserMapper.xml
可以看到下面的参数类型就是复合对象.内部字段#{addr.name}= u.getAddr().getName();
<!-- List<User> getUsersByAddr(User u);
参数是复合类型:直接提取复合对象.内部字段
#{addr.name} = u.getAddr().getName();
-->
<select id="getUsersByAddr" resultType="com.itheima.bean.User">
select * from tb_user where address = #{addr.name}
</select>
2 核心配置文件优化
2.1 mybatis-config.xml的优化
properties优化:
在外部定义了一个db.properties文件存放数据库的连接信息,然后在核心配置文件中通过:
<properties resource="db.properties"></properties>
来关联这个信息。
这样以后我们要修改参数只需找到db.properties修改键值即可。
//db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day18
username=root
password=root
<!-- mybatis-config.xml -->
<!-- 第一种方案-->
<!-- 会自动去src下加载db.properties属性配置文件信息-->
<properties resource="db.properties"></properties>
<!-- 第二种方案-->
<!-- 加载数据库的核心配置信息 resource:自动去类路径src下寻找。
<properties resource="db.properties">
优先用外部配置,如果外部没有这个配置再用这里的配置!
<property name="username" value="root"/>
<property name="password" value="dlei"/>
</properties>
-->
...
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
mybatis的properties配置:
在构造函数中传入
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in, environment, props);
直接使用子标签
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/day18"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
配置 resource 地址
<properties resource="db.properties"></properties>
配置 url 地址:会使用 url 去读取流作为配置
<properties resource="xxx.cn"></properties>
- 在 properties 元素体内指定的属性首先被读取。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
2.2 配置类型别名
<!-- 类型别名 -->
<typeAliases>
<!-- 1、配置User类型的别名为: User-->
<!-- <typeAlias type="com.itheima.bean.User" alias="User"></typeAlias>-->
<!-- 2、可以省略别名设置,那么默认的别名就是类名:User -->
<!-- <typeAlias type="com.itheima.bean.User" ></typeAlias>-->
<!-- 3、使用包扫描(企业级开发思想) 扫描这个包下的全部类型,默认别名用类名-->
<package name="com.itheima.bean"/>
</typeAliases>
这样的好处就是UserMapper.xml里面的 resultType不需要再写路径名,只需要填写别名。
<!--UserMapper.xml-->
<select id="selectAll" resultType="User">
select * from tb_user
</select>
2.3 mappers配置优化
子元素 mapper: 每行语句指定一个映射配置文件
<!-- 直接去src下寻找关联映射文件的路径 -->
<!-- <mapper resource="com\itheima\dao\UserMapper.xml"/>
<mapper resource="com\itheima\dao\StudentMapper.xml"/>-->
子元素 package: 加载包下所有的映射配置文件
<!-- 包扫描:直接扫描该包下的全部映射文件加载!-->
<package name="com.itheima.dao"/>
3 模糊查询
3.1 方案一:%${value}%
直接使用这个值’%${value}%'提取模糊查询的值。
//MybatisDemo
List<User> users = userMapper.getUserByNameLike("天");
//UserMapper
List<User> getUserByNameLike(String userName);
resultType: 如果返回的是集合,使用的就是集合中单个元素的类型!
${value}: 字符串拼接,使用${} 如果是简单类型:(8种基本类型+String类型),这里变量名只能是value!
- ${} 对传递进来的参数原样拼接在SQL中
UserMapper.xml
<!--
List<User> getUserByNameLike(String name);
通过名字模糊查询
-->
<select id="getUserByNameLike" resultType="User">
select * from tb_user where userName like '%${value}%'
</select>
3.2 CONCAT(’%’, #{xxx} , ‘%’)
直接在数据库层面进行前后拼接%.
//MybatisDemo
List<User> users = userMapper.getUserByNameLike2("天");
//UserMapper
List<User> getUserByNameLike2(String userName);
UserMapper.xml
<!-- List<User> getUserByNameLike2(String userName); -->
<!-- 方案二:CONCAT('%', #{xxx} , '%') :在前后拼接% -->
<select id="getUserByNameLike2" resultType="User">
select * from tb_user where userName like CONCAT('%' , #{xxx} , '%')
</select>
3.3 直接在业务查询时做好
直接在业务查询的时候,通过Java代码做好模糊查询的入参就可以了!
name= ‘%天%’
//MybatisDemo
List<User> users = userMapper.getUserByNameLike3("%天%");
//UserMapper
List<User> getUserByNameLike3(String userName);
UserMapper.xml
<!-- List<User> getUserByNameLike3(String userName); -->
<!-- 方案三: 直接在业务查询的时候,通过Java代码做好模糊查询的入参就可以了! -->
<select id="getUserByNameLike3" resultType="User">
select * from tb_user where userName like #{xxzds}
</select>
4 获取主键
插入数据获取被插入数据的主键,有两种方式。
通过LAST_INSERT_ID()获取刚插⼊记录的⾃增主键值,在insert语句执⾏后,执⾏select LAST_INSERT_ID()就可以获取⾃增主键。
原理:先查询序列得到主键,将主键设置到user对象中,将user对象插⼊数据库
// MybatisDemo
User user = new User();
user.setCreateDate(new Date());
user.setLoginName("nvgw");
user.setUserName("朱琳");
user.setPassWord("tangtang");
// int count = userMapper.save(user);
int count = userMapper.save2(user);
//UserMapper
int save(User user);
int save2(User user);
4.1 方式一:子元素<selectKey>
<!-- int save(User user);
方式一:子元素\<selectKey>
-->
<insert id="save" >
INSERT INTO `tb_user` (
`loginName`,
`userName`,
`passWord`,
`create_date`
)
VALUES
(
#{loginName},
#{userName},
#{passWord},
#{createDate}
)
<!--
keyColumn:主键在表中对应的列名
keyProperty:主键在实体类中对应的属性名
resultType:主键的数据类型
order:
BEFORE: 在添加语句前执行查询主键的语句
AFTER: 在添加语句后执行查询主键的语句
原理: user.setId(主键值)
-->
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
</insert>
4.2 直接在insert通过属性获取主键
<!-- int save2(User user); -->
<!-- 方式二:插入数据获取主键,使用属性解决
useGeneratedKeys true 使用自动生成的主键 keyColumn表中主键的列名 keyProperty实体类中主键的属性名
-->
<insert id="save2" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO `tb_user` (
`loginName`,
`userName`,
`passWord`,
`create_date`
)
VALUES
(
#{loginName},
#{userName},
#{passWord},
#{createDate}
)
</insert>
5 resultType与resultMap
<resultMap id="userResultMap" type="User">
<!--colum数据库字段列名 property实体类字段名称-->
<id column="id" property="id"></id>
<result property="username" column="username"/>
</resultMap>
如果实体类中的字段与数据库的列名称不一致,映射数据会失败。
因为,如果我们的数据表的字段和JavaBean的属性名称是相同时,我们就会使用上面的代码。
Mybatis会⾃动帮我们把返回的结果进⾏封装成JavaBean
那当我们数据表的字段和JavaBean的属性名称不是相同时,我们就需要使⽤resultMap。
解决方式有两种:
5.1 自定义结果集配置:ResultMap
//MybatisDemo
List<User> users = userMapper.getUserByNameLike("天");
//UserMapper
List<User> getUserByNameLike(String userName);
如果这里的不使用resultMap,而是使用resultType的话,等下打印出来createDate=null,原因就是实体类中的字段与数据库的列名称不一致。
<!--自定义结果集-->
<resultMap id="userResultMap" type="User">
<!--colum数据库字段列名 property实体类字段名称-->
<id column="id" property="id"></id>
<result column="create_date" property="createDate"></result>
</resultMap>
<!--List<User> getUserByNameLike(String userName);-->
<select id="getUserByNameLike" resultMap="userResultMap">
select * from tb_user where userName like '%${value}%'
</select>
5.2 直接使用查询别名
//MybatisDemo
List<User> users = userMapper.getUserByNameLike2("天");
//UserMapper
List<User> getUserByNameLike2(String userName);
UserMapper.xml
通过配置别名的方式,使得数据库的列名和实体类的名字相同。
<select id="getUserByNameLike2" resultType="User">
select * , create_date createDate from tb_user where userName like '%${value}%'
</select>
5.3 resultType与resultMap区别
resultType :指定输出结果的类型(pojo、简单类型、hashmap…),将sql查询结果映射为java对象。
使⽤resultType注意:sql查询的列名要和resultType指定pojo的属性名相同,指定相同属性⽅可映射成功,如果sql查询的列名要和resultType指定pojo的属性名全部不相同,list中⽆法创建pojo对象的。就会出现createDate=null的情况。
resultMap:将sql查询结果映射为java对象。
如果sql查询列名和最终要映射的pojo的属性名不⼀致,使⽤resultMap将列名和pojo的属性名做⼀个对应关系 (列名和属性名映射配置)。