补充1:新增用户ID的返回值
新增用户后,同时还要返回当前新增用户的id值,一般主键id值是自增的,所以我们可以把新自增的id值返回
SELECT LAST_INSERT_ID();
<selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey> xml
补充2:#{}和${}的区别
1.#{}表示一个占位符 相当于?
2.通过#{}可以实现preparedStatement向占位符中设置值,自动进行类型的转换 java类型和jdbc类型的转换
3.#{}有效防止sql的非法注入
4.#{}可以接收简单的类型或者pojo属性值
5.如果parameteType传输单个简单类型值,#{}括号中可以是value或者是其他名称
6.${}表示字符串的拼接,大多数使用在传输sql字段名
7.使用${}可以将paramentType传入的内容拼接在sql中 不进行类型的转换
8.${}可以接收简单的类型值或者是pojo属性值
9.如果parmentType传输单个简单类型值,${}括号中的只能是value
补充3:mybatis中:mapper.xml中使用比较运算符需要进行转义[> <] = !=
在sql语句中日期可以直接进行大小比较,使用比较运算符 >= <= > < = !=
> ---> 大于号
<--->小于号
或者使用 <![CDATA[ ]]>把需要比较的条件放进[]里面即可
如日期比较:
SELECT * FROM user WHERE <![CDATA[birthday < "2021-2-28"]]>
SELECT * FROM user WHERE birthday > "2021-2-28"
输入映射(parameterType)
? 简单类型
o 基本类型 ---> 整型
o String字符串
? 复杂类型
o pojo
pojo Plain Ordinary Java Object 简单的java对象 实际上就是我们的JavaBean
当传入的参数较多时,使用参数的索引下标 0,1,2,3,4,5,…
可以把参数封装到pojo中,以pojo作为参数进行传递
User Role Department
o pojo的包装类 格式类型Vo
1.内部至少包含一个普通的类,可以进行多条件查询
2.一般用于多个多个对象组成查询条件
比如:查询用户时,用户里面包含角色信息,可能需要把角色信息也要作为查询条件
输出映射(resultType)
resultType 属性可以自豪地暖管结果集类型,它支持基本类型和JavaBean类型
resultType和parameterType一样,如果提前注册过类型的别名,可以直接使用别名(不区分大小写) 如果没有注册过需要使用全限定类名
注意:实体类中的属性名称必须和表中的字段名称(sql查询语句中字段名称)保持一致,否则无法完成封装
? 简单类型
o 基本类型 ---> 整型为主 count()
o String字符串
<select id = "selectUserCount" resultType = "Integer">
select count(*) from user
</select>
<select id "queryUserName" parameterType resultType = "String">
select username from user where id = #{id}
</select>
? 复杂类型
o pojo ---> 单个对象 一条记录 resultType = "user"
o pojo列表 ---> 多个对象 多条记录 存放在数组或者是集合当中 resultType = "user"
问题:当实体类属性和表中的字段名称不一致时,应该怎么封装
使用别名查询(不推荐使用)
<select id = "findAllUsers" resultType = "user">
select id userID,username userName,birthday userBirthday sex userSex
,address as userAddress from user
</select>
如果查询次数较多时,使用别名不方便.
resultMap(推荐使用)
如果查询sql语句较多时,我们可以使用resultMap进行实体类属性和表中的字段进行映射
首先定义resultMap实体类属性和表中的字段进行一一映射
在select标签中引入resultMap结果映射
此外resultMap还可以进行将查询的结果值映射为复杂类型的pojo,比如在查询结果映射对象时,对象可以包括pojo,和List实现一对一查询
和一对多查询.
? id映射:<id column = "表字段名" property = "实体类属性名">
? 非主键映射:<result column = "表字段名" property = "实体类属性名">
<!--使用resultMap 让实体类的属性名称和表中的字段名称保持一致-->
<resultMap id="roleMap" type="role">
<id property="roleId" column="r_id"></id>
<result property="roleName" column="r_name"></result>
<result property="roleDesc" column="r_desc"></result>
<result property="roleUpdateTime" column="r_updateTime"></result>
</resultMap>
<select id="getAllRoles2" resultMap="roleMap">
<!--采用起别名的方式-->
select * from role
</select> xml
? 一对一映射:<assocation property = "实体类属性名"></assocation>
当输出结果是,内部包含了另外一个pojo时,使用resultMap和pojo中的属性映射,可以先在类中声明该pojo属性
其次在mapper.xml文件中通过resultMap使用<assocation property = "实体类属性名"
// pojo类定义
public class User implements Serializable {
/*
* 两个保持一致:数据类型和名称
* */
private int id; // 主键 id
private String username; // 用户名
private Integer age; // 年龄
private String address; // 地址
private String gender; // 性别
// 查询用户时,展示部门的相关信息
private Department department;// pojo
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
<!--查询所有用户信息 里面关联部门信息-->
<resultMap id="userMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="address" column="address"></result>
<result property="gender" column="gender"></result>
<!--映射复杂的pojo类型 一一映射 -->
<association property="department">
<id property="id" column="d_id"></id>
<result property="departmentName" column="d_name"></result>
<result property="departmentDesc" column="d_desc"></result>
<result property="departmentUpdate" column="d_update"></result>
</association>
</resultMap>
<!-- List<User> getTotalUser();-->
<select id="getTotalUser" resultMap="userMap">
select * from user as u,department as d where u.u_did = d.d_id
</select>
要求:该User类和Department类是一一对应的关系 使用标签association
扩展:
可以使用map集合进行映射
当参数传递较多时,该参数涉及到多个pojo,除了我们可以使用pojo或者pojo包装类的形式外,我们还可以使用Map集合形式来实现多参传递
<!--List<User> queryUserByDepartNameAndUsername(Map map);-->
<select id="queryUserByDepartNameAndUsername" parameterType="map" resultType="user">
select * from user u,department d where u.u_did = d.d_id and d.d_id = #{d_id} and u.username = #{username}
</select> xml
接口
List<User> queryUserByDepartNameAndUsername(Map map);
/**
* 查询部门id值为4的部门,并且用户名称为小赵,得到用户信息
*/
@Test
public void testQueryUserByDepartNameAndUsername(){
Map map = new HashMap<>();
map.put("d_id", 4);
map.put("username", "小赵");
List<User> users = userDao.queryUserByDepartNameAndUsername(map);
for (User user : users) {
System.out.println(user);
}
}
? 一对多映射:<collection property = "实体类属性名" ofType="容器中的数据类型 List"></collection>
查询部门表时,需要首先展示部门信息,还要展示该部门下的所有用户信息
步骤:
首先需要在实体类中定义该pojo类的属性 属性的类型为容器类型List
其次在mapper.xml文件中定义resultMap的一对多映射 用户--->角色
在select标签中引入resultMap引用.
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
private Date roleUpdateTime;
//角色---> 一对多的关系
private List<User> users; java
<resultMap id="roleMap" type="role">
<id property="roleId" column="r_id"></id>
<result property="roleName" column="r_name"></result>
<result property="roleDesc" column="r_desc"></result>
<result property="roleUpdateTime" column="r_updateTime"></result>
<!--角色和用户是一对多的关系-->
<!--
ofType 对于容器类型我们采用指定容器中数据的类型,使用属性ofType
javaType 代表users本身的是类型,List类型
-->
<collection property="users" ofType="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="address" column="address"></result>
<result property="gender" column="gender"></result>
</collection>
</resultMap>
xml
<!--List<User> queryUserByDepartNameAndUsername(Map map);-->
<select id="queryUserByDepartNameAndUsername" parameterType="map" resultType="user">
select * from user u,department d where u.u_did = d.d_id and d.d_id = #{d_id} and u.username = #{username}
</select> xml
/**
* 查询部门id值为4的部门,并且用户名称为小赵,得到用户信息
*/
@Test
public void testQueryUserByDepartNameAndUsername(){
Map map = new HashMap<>();
map.put("d_id", 4);
map.put("username", "小赵");
List<User> users = userDao.queryUserByDepartNameAndUsername(map);
for (User user : users) {
System.out.println(user);
}
} java
动态sql
动态 SQL 是 MyBatis 的强大特性之一。解决了根据不同条件拼接SQL语句的不便
借助功能强大的基于 OGNL 的表达式
? if
? choose (when, otherwise)
? trim (where, set)
? foreach
? sql
If
常常用于字符串的非空判断
<!--List<User> queryUsersBySex(String sex);-->
<select id="queryUsersByGender" resultType="user">
<!--select * from user where gender = #{gender} -->
select * from user where 1 = 1
<if test=" gender != '' and gender != null">
and gender = #{gender}
</if>
<if test=" username != '' and username != null">
and username like '%' #{username} '%'
</if>
</select>
// 使用动态sql 标签 if
List<User> queryUsersByGender(@Param("gender") String gender,@Param("username") String username);
/**
* 测试动态sql 标签 if
*/
@Test
public void testQueryUsersBySex(){
List<User> users = userDao.queryUsersByGender("男","大叔");
for (User user : users) {
System.out.println(user);
}
}
choose (when, otherwise)
有时候,我们不想使用所有的条件,而只是从这些条件之中选择一个使用,Mybatis提供了choose标签
<!--User queryUserByCondition(String username,String address,int age);-->
<!--使用choose标签-->
<select id="queryUserByCondition" resultType="user">
<!--select * from user where username like '%'#{username} '%' and address = #{address} and age < #{age};-->
select * from user where 1=1
<choose>
<when test="username != null and username != ''">
and username like '%' #{username} '%'
</when>
<when test="address != null and address != ''">
and address = #{address}
</when>
<otherwise>
age < #{age}
</otherwise>
</choose>
</select>
// 使用动态sql 标签 choose
List<User> queryUserByCondition(@Param("username") String username, @Param("address") String address,@Param("age") int age);
/**
* 测试动态sql 标签 choose when情形是互斥的
*/
@Test
public void testQueryUserByCondition(){
List<User> user = userDao.queryUserByCondition("花", "河南信阳", 20);
System.out.println(user);
}
trim(where set)
where 可以去掉第一个and
set 用于动态更新语句。set标签可以用于动态包含需要更新的字段,忽略其他不更新的字段。
where
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除
<!--List<User> queryUserByAgeAndDid(@Param("age") int age,@Param("u_did") int u_did);-->
<!--测试动态sql where标签-->
<select id="queryUserByAgeAndDid" resultType="user">
<!-- select * from user where age < #{age} and u_did < #{u_did} -->
select * from user
<where>
<if test="age != '' and age != null">
age < #{age}
</if>
<if test="u_did <= 2">
and age < #{age}
</if>
</where>
</select>
// 使用动态sql 标签 where
List<User> queryUserByAgeAndDid(@Param("age") int age,@Param("u_did") int u_did);
/**
* 测试动态sql 标签 where
*/
@Test
public void testQueryUserByAgeAndDid() {
// 年龄 < 20 部门id值 > 2
List<User> users = userDao.queryUserByAgeAndDid(20, 2);
for (User user : users) {
System.out.println(user);
}
}
set
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
<!--void updateUserByNecessary(User user);-->
<!--测试动态标签 set -->
<update id="updateUserByNecessary" parameterType="user">
<!--update user set username = #{username},age = #{age},address = #{address},gender = #{gender} where id = #{id}-->
update user
<set>
<if test="username != '' and username != null">username = #{username},</if>
<if test="age > 0"> age = #{age},</if>
<if test="address != '' and address != null">address = #{address},</if>
<if test="gender != '' and gender != null">gender = #{gender}</if>
</set>
<where>
<if test="id > 0">
id = #{id}
</if>
</where>
</update>
// 使用动态sql标签 set
void updateUserByNecessary(User user);
/**
* 测试动态sql标签 set
*/
@Test
public void testUpdateUserByNecessary() {
User user = new User("马大神2",0,"","");
user.setId(4);
userDao.updateUserByNecessary(user);
}
sql片段
可以把多次出现的sql封装为一个片段,在使用的时候,进行引用。
sql中将重复的sql提取出来,使用时使用标签include标签引用即可,最终达到sql重用的目的。
示例如下:
select * from user
<!--把select * from user提取到sql片段中-->
<sql id = "selectUser">
select * from user
</sql>
<!--根据性别和姓名查询用户信息-->
<select id = "findUserByGenderAndUsername" parameterType = "user" resultType = "user">
<!--select * from user where gender = #{gender} and username like '%' #{username} '%'-->
<include refid = "selectUser"/> <!--相当于 select * from user -->
<where>
<if test = "gender != '' and gender != null">
gender = #{gender}
</if>
<if test = "username != '' and username != null">
username = #{username}
</if>
</where>
</select>
foreach
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach
尤其是在构建 IN 条件语句的时候使用的,select * from user where id in(1,3,5,7);
示例如下:
<!--
使用动态标签 foreach
List<User> queryUserByIds(List<Integer> ids);
-->
<sql id="selectUser">
select * from user
</sql>
<!--list集合-->
<select id="queryUserByIds" parameterType="list" resultType="user">
<include refid="selectUser"/>
<where>
<!-- id in(1,3,5,7,9) -->
<foreach collection="list" item="id" open="id in (" close=" )" separator=",">
#{id}
</foreach>
</where>
</select>
<!--数组-->
<select id="queryUserByIds" parameterType="java.util.Arrays" resultType="user">
<include refid="selectUser"/>
<where>
<!-- id in(1,3,5,7,9) -->
<foreach collection="array" item="id" open="id in (" close=" )" separator=",">
#{id}
</foreach>
</where>
</select>
// 使用动态标签 foreach
List<User> queryUserByIds(List<Integer> ids);
List<User> queryUserByIds(Integer[] ids);
/**
* 测试动态sql标签 foreach
*
*/
@Test
public void testQueryUserByIds() {
ArrayList<Integer> list = new ArrayList<>();
// (1,3,11,19)
list.add(1);
list.add(3);
list.add(11);
list.add(19);
Integer[] ids = {1, 3, 11, 19};
//List<User> users = userDao.queryUserByIds(list);
List<User> users = userDao.queryUserByIds(ids);
for (User user : users) {
System.out.println(user);
}
}
注意事项 :
如果传入的是数组 collection需要使用arrays
如果传入的是list集合,collection需要使用list
关联查询
用户表 角色表
1 ---> 1
n <---- 1
一个模块 其实就是一张表
一个模块内的信息关联其他模块的信息
模块与模块之间的关联 ----> 表与表之间的关联
两张表的关联
三张表的关联
.......
多表查询
用户模块 角色模块
user role
1 ---> 1 一 一映射 多对一
n <---- 1 一对多映射 多对多
权限模块 角色模块
1 n
n 1
多对多映射 ----> 两个一对多映射
中间表
auth_role
auth_id role_id
实体类关联
// 多对多映射
public class Auth implements Serializable{
//..... 自己固有属性
private List<Role> roles;
// get和set方法
//....
}
public class Role implements Serializable{
//..... 自己固有属性
private List<Auth> auths;
private List<User> users;
// get和set方法
//....
}
// 一对多映射
public class User implements Serializable{
//..... 自己固有属性
private Role role;
// get和set方法
//....
}
mybatis事务
Connection setAutoCommit(boolean autoCommit) false 代表就是开启事务 只影响增删改操作 不影响查询操作
mybatis默认是开启事务的,如果想要把事务关闭,可以设置autoCommit为true。
可以借助于SqlSessionFactory 类 中的openSession方法 设置autoCommit为true,手动关闭mybatis的事务。
什么是事务?
相关文章
- 02-24Spring Boot2 系列教程(二十一)整合 MyBatis
- 02-24mybatis-注解版<2>动态sql的bug
- 02-24玩转springboot2.x 通过自定义配置类整合Druid(mybatis版)
- 02-24SpringBoot2.X整合Mybatis实现增删改查(注解版)
- 02-24SpringBoot2.x系列教程02-springboot整合Mybatis
- 02-24SpringBoot2整合Mybatis拦截器,拦截mapper接口的某个方法
- 02-24阿里Java学习路线:阶段 2:数据库开发-SQL进阶及查询练习:课时6:非空和唯一约束
- 02-24SSMday2——掌握MyBatis的核心对象
- 02-24Java MyBatis 创建SqlSessionFactory和获取SqlSession的方法及示例代码
- 02-24HOW2J 全套教程整理:Java、前端、数据库、中间件、第三方、项目、面试题