java mybatis(补充2)

补充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语句中日期可以直接进行大小比较,使用比较运算符 >= <= > < = !=
&gt;  ---> 大于号
&lt;--->小于号
或者使用  <![CDATA[  ]]>把需要比较的条件放进[]里面即可
如日期比较:
SELECT * FROM user WHERE <![CDATA[birthday < "2021-2-28"]]>
SELECT * FROM user WHERE birthday &gt; "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 &lt; #{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 &lt; #{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 &lt; #{age} and u_did &lt; #{u_did} -->
select * from user
<where>
  <if test="age != '' and age != null">
      age &lt; #{age}
  </if>
  <if test="u_did &lt;= 2">
     and age &lt; #{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 &gt; 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 &gt; 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的事务。
什么是事务?

上一篇:java-将不同类型的对象排序到一个列表中


下一篇:使用mybatis插件自动生成实体(pojo)类