MyBatis框架知识点大全,从0到1(配置文件和使用、手动和全自动映射、lombok使用、Mybatis测试工具类、动态SQL、通过注解来实现动态SQL和手动一对一、一对多、多对多映射)

MyBatis框架

这里写的感觉有点多,到时候拆开发,需要哪看目录就好🤗

ORM(对象关系映射

ORM即对象关系映射(Object-Relationl Mapping),它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。

配置环境和文件

1.mybatis所需jar

必须:

<mybatis.version>3.2.8</mybatis.version>
<slf4j.version>1.7.12</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<druid.version>1.0.9</druid.version>

<!-- mybatis框架包 -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>${mybatis.version}</version>
</dependency>
<!--mysql驱动-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.35</version>
</dependency>

非必需:

<!-- log -->
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>${log4j.version}</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>${slf4j.version}</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>${slf4j.version}</version>
</dependency>
<!-- lombok(这个后面会说) -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.8</version>
</dependency>

2.创建主配置文件mybatis-config.xml相关配置

注:可以点击configuration标签来查看写入标签的顺序,参数标签可以不写但是顺序不能倒置

    <configuration>
    <!--引入properties文件-->
    <properties resource="jdbc.properties"></properties>
    <settings>
       <!--  配置打印SQL语句 
			value="STDOUT_LOGGING"(在控制台打印sql) 				value="LOG4J"(将打印的sql放置到log4j日志文件中)-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--
        设置Mybatis的自动映射模式
            FULL:全自动映射(可映射复杂数据类型,但是影响性能)
            NONE:关闭自动映射,全手动映射
            PARTIAL:默认半自动映射
         -->
<!--        <setting name="autoMappingBehavior" value="FULL"/>-->
    </settings>
    <!-- 简化包名(起个别名) -->
    <typeAliases>
        <package name="com.r.pojo"/>
    </typeAliases>
    <!-- 创建数据源 默认加载rr,可以有多个数据源 -->
    <environments default="rr">
        <environment id="rr">
            <!-- 事务的加载类型:比如jdbc -->
            <transactionManager type="JDBC"></transactionManager>
     		<!--连接信息-->
            <!--
                dataSource—数据源,type属性、其有三种取值:
                        "POOLED":使用连接池
                        "JNDI":和tomcat关联性比较大,不推荐
                        "UNPOOLED":不使用连接池
             -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 扫描mapper文件,不要忘记添新的!!! -->
    <mappers>
        <mapper resource="mapper/ProviderDao.xml"/>
        <mapper resource="mapper/UserVoMapper.xml"/>
    </mappers>
</configuration>

3. 编写测试类

String resource = "mybatis-config.xml";
try {
    InputStream is = Resources.getResourceAsStream(resource);
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
    /**
     * true 自动提交事务 (默认)
     * false 关闭自动提交
     * 不写可能会导致增加、更新和删除的成功但数据库没有改的现象
     */
    SqlSession sqlSession = factory.openSession(true);
    UserVoDao userVoDao = sqlSession.getMapper(UserVoDao.class);
    userVoDao.getUserId(10);
    //关闭sqlsession
    sqlSession.close();
} catch (IOException e) {
    e.printStackTrace();
}

SQL映射的XML文件

SQL映射文件的几个元素(按照定义的顺序)

  • mapper – namespace
  • cache – 配置给定命名空间的缓存
  • cache-ref – 从其他命名空间引用缓存配置
  • resultMap –用来描述数据库结果集和对象的对应关系
  • sql – 可以重用的SQL块,也可以被其他语句引用
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

SQL映射文件

文件形式一般为:~mapper.xml或是~dao.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="命名空间(全路径)">
    
    <!--方法名与ID必须一致-->
    <!--parameterType 传入参数类型-->
    <!--resultType 返回值类型-->
    <select id="接口方法名"
            resultType="返回值类型"
            parameterType="参数类型" >
        	这里是写sql语句的地方
    </select>
</mapper>

SQL映射文件参数传递

文件形式一般为:~mapper.java或是~dao.java

接口层

单参数

接口中定义:

public Provider findProviderById(Long id);

映射文件中代码:

<select id="findProviderById"
        resultType="Provider"
        parameterType="long" >
    select * from jntm_provider where id = #{id}
</select>
多个参数

使用注解@Param (作用:起个别名)

(如果别名类型是对象的话那映射文件中sql就用 别名.属性

接口中定义:

public int updateProviderInfo(@Param("name") String proName, @Param("id") Long id);

映射文件中代码:

<!-- 注意:parameterType为对象名 -->
<update id="updateProviderInfo" parameterType="Provider">	
        update jntm_provider set proName = #{name} where id = #{id}
</update>
使用map集合

可用于多条件查询,或多个对象传回一个对象的类型

接口中定义:

public List<User> findUserInfo(Map<String, Object> map);

映射文件中代码:

<select id="findUserInfo"
        resultType="User">
    <!-- 用map来传值的时候#{}里面的值为map的key -->
    <!--
        #与$区别:
                #:是占位符
                $:是原样输出
  所以可以有下面的两种写法,但$不推荐
     -->
    select * from jntm_user
    where userName like concat ('%', #{name}, '%') and
    address like  '%${address}%' and
    gender = #{sex}
</select>

测试类:

 @Test
    public void findUserInfo() {
        SqlSession sqlSession = MyBatisUtil.createSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);

        Map<String, Object> map = new HashMap<>();
        map.put("name", "Hank");
        map.put("sex", 1);
        map.put("address", "温馨的小窝");

        List<User> users = userDao.findUserInfo(map);
        System.out.println(users.size());

        MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
    }

SQL映射文件获取关系值

一对一

对象套对象:association

实体类:

添上一行

//一对一
private Role role;

然后getter()、setter()

映射文件代码:

<!--  手动映射  -->
<resultMap id="userResult" type="User">
    <id property="id" column="id"/>
    <result property="userName" column="name"/>
    <!-- 一对一映射:
				property是上面实体类属性名
				javaType是被映射的实体类名
 	-->
    <association property="role" javaType="Role">
        <result property="roleName" column="roleName"/>
    </association>
</resultMap>

<select id="findUserById" resultType="User" resultMap="userResult">
    select a.id,a.userCode,a.userName as name,a.userPassword,b.roleName from jntm_user a
    left join jntm_role b on a.userRole = b.id
    where a.id = #{id}
</select>
一对多

对象套集合:collection

实体类:

添上一行

//一对多
private List<Address> addressList;

然后getter()、setter()

映射文件代码:

<!--  手动映射  -->
<resultMap id="userResultAddress" type="User">
    <id property="id" column="id"/>
    <result property="userName" column="userName"/>
    <!-- 一对多映射:
      property是上面实体类属性名
     ofType是被映射的实体类名(注意和一对一的不一样嗷~)
  -->
    <collection property="addressList" ofType="Address">
        <result property="contact" column="contact"/>
        <result property="addressDesc" column="addressDesc"/>
    </collection>
</resultMap>

<select id="findUserAddress" resultType="User" resultMap="userResultAddress">
    SELECT a.id,a.userName,b.contact,b.addressDesc FROM jntm_user a
    LEFT JOIN jntm_address b ON a.id = b.userId
    WHERE a.id = #{id}
</select>
全自动映射的情况

映射文件可以这样写:

<resultMap id="userResult" type="User">
    <id property="id" column="id"/>
    <result property="userName" column="name"/>
    <!-- 一对一映射:
				property是上面实体类属性名
				javaType是被映射的实体类名
 	-->
    <association property="role" javaType="Role">
     	 <!-- 是的这里什么都没有 -->	
    </association>
</resultMap>

<select id="findUserById" resultType="User" resultMap="userResult">
    select a.id,a.userCode,a.userName as name,a.userPassword,b.roleName from jntm_user a
    left join jntm_role b on a.userRole = b.id
    where a.id = #{id}
</select>

这样就能映射上,但是不推荐全自动映射,因为把所有的都自动映射上了,性能会降低

简化实体类的插件工具:Lombok

使用方法

Maven导入(上面如果导了的话这个就不用了)

pom.xml:

<!-- 导入lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.16</version>
    </dependency>

然后来到你的实体类,加个注解,这样就可以不用getter()和setter()了:

@Data	//比如这样
public class UserVo {
    //我是属性
}
  • @Data:什么都有,比如getter()、setter()、toString()、RequiredArgsConstructor()等等…

  • @Getter:单纯的getter()

  • @Setter:有单纯的getter()就也有单纯的setter()咯~

  • @ToString:重写toString方法

  • @NoArgsConstructor:无参构造方法

  • @AllArgsConstructor:所有有参构造方法

  • @NonNull:添加空指针检查

还有一堆,简单知道一下就够用了😬

MyBatis测试工具类

MyBatisUtil.java

package com.r.util;

import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtil {
	private static SqlSessionFactory factory;
	
	static{
        
        //在静态代码块下,factory只会被创建一次
		System.out.println("static factory===============");
		try {
			InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
			factory = new SqlSessionFactoryBuilder().build(is);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
	
	public static SqlSession createSqlSession(){
		return factory.openSession(true);//true 为自动提交事务
	}
	
	public static void closeSqlSession(SqlSession sqlSession){
		if(null != sqlSession) 
			sqlSession.close();
	}
}

测试类使用时,方法就两个:

SqlSession sqlSession = MyBatisUtil.createSqlSession();		//创建
ProviderDao providerDao = sqlSession.getMapper(ProviderDao.class);	//DAO层接口实现

//int n = providerDao.updateProviderInfo("xxx公司",25L);	//写的具体方法
//System.out.println("受影响行数:" + n);

MyBatisUtil.closeSqlSession(sqlSession);    //释放资源

tips:用这个可以方便很多重复代码,下面的示例测试类中都用了这个

动态SQL

if + where(查询)

<select id="findUserList" resultType="User">
        select * from jntm_user
        <where>
            <if test="uName != null">
                userName like concat ('%', #{uName} ,'%')
            </if>
            <if test="beginBirthday != null">
                and birthday &gt; #{beginBirthday}
            </if>
            <if test="endBirthday !=null">
                and birthday &lt; #{endBirthday}
            </if>
        </where>
        order by birthday desc limit #{pyl},#{pageSize}
</select>

<where>标签会自动不要第一个and,如果<if>标签里面都为null,那么就相当于

<where>
    里面什么都没有嗷~
</where>

来实现动态sql的目的

  • 注:
    • &gt;:大于号>
    • &lt;:小于号<

if + trim(都可以,但不推荐,一般用于insert)

<insert id="insertUserInfo">
    insert into jntm_user
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="userCode != null">userCode,</if>
        <if test="userName != null">userName,</if>
        <if test="userPassword != null">userPassword,</if>
        <if test="gender != null">gender,</if>
        <if test="birthday != null">birthday,</if>
        <if test="phone != null">phone,</if>
        <if test="role != null">userRole,</if>
    </trim>
    values
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="userCode != null">#{userCode},</if>
        <if test="userName != null">#{userName},</if>
        <if test="userPassword != null">#{userPassword},</if>
        <if test="gender != null">#{gender},</if>
        <if test="birthday != null">#{birthday},</if>
        <if test="phone != null">#{phone},</if>
        <if test="role != null">#{role.id},</if>
    </trim>
</insert>
  • prefix: 给sql语句拼接的前缀
  • suffix: 给sql语句拼接的后缀
  • prefixOverrides:去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
  • suffixOverrides:去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定

if + set(修改)

<update id="updateUserInfo">
    update jntm_user
    <set>
        <if test="userCode != null">userCode = #{userCode},</if>
        <if test="userName != null">userName = #{userName},</if>
        <if test="userPassword != null">userPassword = #{userPassword},</if>
        <if test="phone != null">phone = #{phone}</if>
    </set>
    where id = #{id}
</update>

foreach(遍历)

三种情况:

List集合入参

dao层接口

/**
     * 根据多个角色id查找用户集合
     * list集合入参
     * @param roleids
     * @return
     */
public List<User> findUserLists(List<Integer> roleids);

映射文件:

<select id="findUserLists" resultType="User">
    select * from jntm_user where userRole in
    <foreach item="ids" collection="list" open="(" separator="," close=")">
        #{ids}
    </foreach>
</select>
  • 单参数时,collection这里要写类型:
    • list:集合
    • array:数组
    • map-key(写自己map的key名)
  • 多参数时,写接口中设置的相应(集合/数组)参数名或map中key名

item:自己设一个用于遍历的值名就行

open:前缀

separator: 中间以什么隔开

close:后缀

测试类:

@Test
public void findUserLists() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    List<User> userList = userDao.findUserLists(list);
    for (User user : userList) {
        System.out.println(user.toString());
    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}
数组入参

dao层接口

 /**
     * 根据多个角色id和性别查找用户
     * 数组入参
     * @param roleids
     * @return
     */
public List<User> findUserArrays(@Param("roleids") Integer[] roleids,
                                 @Param("gender") Integer gender);

映射文件:

<select id="findUserArrays" resultType="User">
    select * from jntm_user where userRole in
    <foreach item="ids" collection="roleids" open="(" separator="," close=")">
        #{ids}
    </foreach>
    and gender = #{gender}
</select>

与上面解释一样,因为是多参数,所以此处collection中没有写array而是写了接口的参数名

测试类:

@Test
public void findUserArrays() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);

    List<User> userList = userDao.findUserArrays(new Integer[]{1, 2}, 1);
    for (User user : userList) {
        System.out.println(user.toString());
    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}
Map入参

dao层接口

    /**
     * 根据多个角色id和性别查找用户
     * Map入参
     * @param map
     * @return
     */
    public List<User> findUserMaps(Map<String, Object> map);

映射文件:

<select id="findUserMaps" resultType="User">
    select * from jntm_user where userRole in
    <foreach item="ids" collection="roleids" open="(" separator="," close=")">
        #{ids}
    </foreach>
    and gender = #{gender}
</select>

这里的collection#{gender}均为下面测试类中map对象的key名,要对应好

测试类:

@Test
public void findUserMaps() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    Map<String, Object> map = new HashMap<>();
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    map.put("roleids", list);
    map.put("gender", 1);

    List<User> userList = userDao.findUserMaps(map);
    for (User user : userList) {
        System.out.println(user.toString());
    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}

choose(when otherwise)

相当于if-elseif,和JSTL中的语法差不多

test 里面不止可以写 =、也可以 ><

<when>相当于elseif

<otherwise>相当于else

<!-- 语法 -->
<choose>
    <when test ="条件1"></when>
    <when test ="条件2"></when>
    <when test ="条件3"></when><otherwise></otherwise>
</choose>   

用到的情况比较少,就写了一个不太和逻辑的小例子,但是意思是那么个意思

dao层接口

/**
     * 只修改用户其中一个字段的信息
     * @param user
     * @return
     */
public int updateUserInfo1(User user);

映射文件:

<!-- 哪个不为空就改哪个,多个不为空则只改sql语句靠前的第一个条件 -->
<update id="updateUserInfo1">
    update smbms_user
    <set>
        <choose>
            <when test="userCode != null">userCode = #{userCode},</when>
            <when test="userName != null">userName = #{userName},</when>
            <when test="userPassword != null">userPassword = #{userPassword},</when>
            <when test="phone != null">phone = #{phone}</when>
            <otherwise><!-- 这里什么也没写(因不符合当前小例子情况),如果什么都不写会返回所有,如果是查询语句数据量非常大的情况而这里不写的话,就是一个深渊巨坑哈哈哈 --></otherwise>
        </choose>
    </set>
    where id = #{id}
</update>

测试类:

@Test
public void updateUserInfo1() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);

    User user = new User();
    //哪个不为空就改哪个,多个不为空则只改sql语句靠前的第一个条件
    user.setUserCode("2222");	//也就是如果先改了这一行,则下行就不会执行了,只改了一行
    user.setUserName("Rose的Hank");	
    
    user.setId(17);


    int n = userDao.updateUserInfo1(user);
    System.out.println("受影响行数:" + n);

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}

sql片段

当映射文件sql语句中存在一些重复代码时来使用,说白了就是代码复用,也方便了不少

<!-- 语法 -->

<!-- 建立sql片段 -->
<sql id="Tuerlechat">	
        ......
</sql>

SELECT * FROM XXX
<trim prefix="where" prefixOverrides="and ">
    <!-- 调用sql片段, 标签include -->
   <include refid="Tuerlechat"/>
</trim>

tips:建立sql片段中的id和调用sql片段中的refid要一致嗷~

多条件查询翻页和记录总条数的小示例

因为翻页和记录总条数中的一些条件代码都一致,所以就用这个写个小示例😎

dao层接口

/**
     * 多条件查询加翻页
     * @param uName
     * @param beginBirthday
     * @param endBirthday
     * 上面的参数是查询的条件,下面这两个是用来翻页的
     * @param pyl
     * @param pageSize
     * @return
     */
public List<User> findUserList(
    @Param("uName") String uName,
    @Param("beginBirthday") String beginBirthday,
    @Param("endBirthday") String endBirthday,
    @Param("pyl") Integer pyl,
    @Param("pageSize") Integer pageSize);

/**
     * 查询总记录数
     * @return
     */
public int findUserListCount(
    @Param("uName") String uName,
    @Param("beginBirthday") String beginBirthday,
    @Param("endBirthday") String endBirthday);

映射文件:

<!-- 这里是sql片段 -->
<sql id="sql_where">
    <where>
        <if test="uName != null">
            userName like concat ('%', #{uName} ,'%')
        </if>
        <if test="beginBirthday != null">
            and birthday &gt; #{beginBirthday}
        </if>
        <if test="endBirthday !=null">
            and birthday &lt; #{endBirthday}
        </if>
    </where>
</sql>



<!-- 这里是sql语句 -->
<select id="findUserList" resultType="User">
    select * from jntm_user
    <include refid="sql_where"></include>
    order by birthday desc limit #{pyl},#{pageSize}
</select>

<select id="findUserListCount" resultType="Integer">
    select count(1) from jntm_user
    <include refid="sql_where"></include>
</select>

这样就都是可以共用的😎

Mybatis通过注解实现动态sql和手动映射

注解实现普通sql

@Select

/**
     * 根据id查用户
     * @param id
     * @return
     */
//这里直接正常这么写就行
@Select("select * from jntm_user where id = #{id}")
public User findUserById1(Integer id);

@Insert

@Insert("insert into jntm_user (userCode,userName) values ("222","kuma")")
public User insertUserInfo();

@Update

@Update("update jntm_user set userName = #{name} where id = #{id}")
public int updateUserInfo(@Param("name") String userName, 
                          @Param("id") Integer id);

@Delete

@Delete("delete from jntm_user where id = #{id}")
public User deleteUserById(Integer id);

注解实现动态sql

两种方式实现:

1、在注解里面写<script>脚本

dao层接口

/**
     * 根据是否传id返回相应用户信息(可能集合可能单个对象)
     * 使用注解查询动态sql(第一种方式)
     * @param map
     * @return
     */
@Select("<script> " +
        "select * from smbms_user" +
        "<where>" +
        "<if test = \" id != null and id != '' \"> " +
        "id = #{id} " +
        "</if>" +
        "</where>" +
        "</script>")
List<User> findUserByCondition(Map<String, Object> map);

测试类:

@Test
public void findUserByCondition() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    Map<String, Object> map = new HashMap<>();
    //map.put("id", 17);	看看效果

    List<User> userList = userDao.findUserByCondition(map);
    for (User user : userList) {
        System.out.println(user.toString());
    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}
2、使用@SelectProvider注解

dao层接口

/**
     * 根据相应条件返回集合或单个对象
     * 使用注解查询动态sql(第二种方式)
     * @param user
     * @return
     */
@SelectProvider(type = UserXXX.class, method = "findUserByCondition1")
List<User> findUserByCondition1(User user);

type:是用来写动态sql的类

method:是上面那个类中的sql对应实现方法

UserXXX.java

/**
 *
 * @Author Tuerlechat,
 * @Date 2022/10/27
 */
public class UserXXX {
    //使用@SelectProvider注解
    @SelectProvider
    //这里是方法名
    public String findUserByCondition1(User user) {
        //返回个SQL(){}.toString();
       return new SQL() {
           {	
               //开始写sql...
               SELECT(" * ");
               FROM("jntm_user").WHERE("1 = 1");
               if ((user.getUserCode()) != null) {
                   WHERE("userCode like concat ('%', #{userCode}, '%')");
               }
               if ((user.getUserName()) != null) {
                   WHERE("userName like '%${userName}%'");
               }
           }
       }.toString();
    }

}

测试类:

@Test
public void findUserByCondition1() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    
    User user = new User();
    user.setUserCode("2");
    user.setUserName("朴");
    
    List<User> userList = userDao.findUserByCondition1(user);
    for (User u : userList) {
        System.out.println(u.toString());
    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}

注解实现手动映射

两种方式实现:

1、一体的写:直接在注解里设置映射

sql语句是连表的,映射的属性property对应的对象写到具体属性一级来一一对应,和正常的语句流程感觉还是差不多的

/**
     * 根据id查询用户信息和角色名
     * 一对一
     * @param id
     * @return
     */
@Results(id = "userResult1", value = {
    @Result(id = true, property = "id", column = "uid"),
    @Result(property = "userName", column = "userName"),
    @Result(property = "role.id", column = "rid"),
    @Result(property = "role.roleName", column = "roleName")
})
@Select("select u.id uid,u.userName,r.id rid,r.roleName from jntm_user u,jntm_role r where u.userRole = r.id and u.id = #{id}")
public User findUserById11(Integer id);
2、分着写:用注解@One和@Many

这个写起来刚开始会有一点点不适应,找了一堆资料也都没有说的很明白的,只能自己摸索,踩了个大坑😑

使用时注意事项:

虽然只是用到了dao层接口,用不到映射文件,但是映射文件也必须创建!!!没错是必须,写个命名空间然后空着就行,导致运行一直报错,搞的脑子都混了🤮

语法:

@Insert("sql语句")	//插入
@Update("sql语句")	//更新
@Delete("sql语句")	//删除
@Select("sql语句")	//查询
//映射集
@Results({
            @Result(id = true, property = "", column = ""),
            @Result(property = "", column = ""),
    
    //省略一些映射字段。。。
    
    
    		//需要一对一(或一对多和多对多)的字段
            @Result(property = "",  //要封装的属性名称
                    column = "",  //根据当前表中的哪个字段来去查询目标表的数据(就是相关联的那一部分(外键))
                    javaType = ,  //要封装的实体类型
                    one = @One(select = "")	//全限定名的要引用的另一个dao接口的方法
                    //一对多是这个,和上面的@One用法一样
                    //many = @Many(select = "")
            )
    })
  • @One:一对一结果集封装
  • @Many:一对多结果集封装
示例
一对一

还是上面那个例子,不过写法不同

根据id查询用户信息和角色名

User实体类:

@Data
public class User {
    //此处省略一些字段。。。
    
	//一对一
	private Role role;	//返回类型是对象
}

UserDao:

/**
     * 根据id查询用户信息和角色名
     * 一对一结果集封装 @one
     * @param id
     * @return
     */
@Results({
    @Result(id = true, property = "id", column = "id"),
    @Result(property = "userCode", column = "userCode"),
    @Result(property = "userName", column = "userName"),
    @Result(property = "role",  //要封装的实体属性名
            column = "userRole",  //根据哪个字段去查询目标表的数据
            javaType = Role.class,  //要封装的的目标方法返回值类型
            one = @One(select = "com.r.dao.RoleDao.findRoleById")
           )
})
@Select("select * from jntm_user where id=#{id}")
public User findUserById11(Integer id);

RoleDao:

/**
     * 根据id查询角色信息
     * @param id
     * @return
     */
@Select("select * from jntm_role where id = #{id}")
public Role findRoleById(Integer id);
一对多

根据id查询用户多个地址

User实体类:

@Data
public class User {
    //此处省略一些字段。。。
    
	//一对多
	private List<Address> addressList;
}

UserDao:

/**
     * 根据id查询用户多个地址
     * 一对多
     * @param id
     * @return
     */
@Results({
    @Result(id = true, property = "id", column = "id"),
    @Result(property = "userCode", column = "userCode"),
    @Result(property = "userName", column = "userName"),
    @Result(property = "addressList",	//要封装的实体属性名
            column = "id",	//根据哪个字段去查询目标表的数据
            javaType = List.class,	//要封装的目标方法返回值类型
            many = @Many(select = "com.r.dao.AddressDao.findAddress")	//@many
           )
})
@Select("select * from jntm_user where id = #{id}")
public User findUserAddress11(Integer id);

AddressDao:

/**
     * 查询地址信息
     * @return
     */
@Select("select * from jntm_address")
//如果是全表都可以一对多映射的话则打开此映射集,因为这个例子里User返回的是单个对象,而Address返回的是List集合,开启此映射集会互相映射,会报错,若使用应将两个方法都改成一致的返回值类型,像本例这样不使用但也可以单方面映射自己需要的信息
//    @Results({
//        @Result( property = "contact", column = "contact"),
//        @Result(property = "addressDesc", column = "addressDesc"),
//        @Result(property = "user",
//                column = "userId",
//                javaType = User.class,
//                one = @One(select = "com.r.dao.UserDao.findUserAddress11")	//@One
//        )
//    })
public List<Address> findAddress();
多对多

一个User有多个Role,一个Role也有多个User

tips:练习库没有类似情况,所以只是写个示例

User实体类:

@Data
public class User {
    //此处省略一些字段。。。
    
	//多对多
	private List<Role> roleList;
}

Role实体类(如果是一体写RoleDao则不需要设置,但分着写需要映射):

@Data
public class Role {
    //此处省略一些字段。。。
    
	//多对多
	private List<Role> roleList;
}

UserDao:

/**
     * 根据id查询用户信息和角色名
     * 多对多结果集封装 @Many
     * @return
     */
@Results({
    @Result(id = true, property = "id", column = "id"),
    @Result(property = "userCode", column = "userCode"),
    @Result(property = "userName", column = "userName"),
    @Result(property = "address", column = "address"),
    @Result(property = "roleList",  //要封装的属性名称
            column = "userRole",  //根据哪个字段去查询目标表的数据
            javaType = List.class,  //要封装的实体类型
            many = @Many(select = "com.r.dao.RoleDao.findRoleById1")
           )
})
@Select("select * from jntm_user")
public List<User> findUserById111();

RoleDao:

/**
     * 根据id查询角色信息
     * @return
     */
// 一体写法 @Select("select * from jntm_role a, smbms_user b where a.id = b.userRole and a.id = #{id}")
//分着写,记得加实体类
@Results({
    @Result(property = "roleName", column = "roleName"),
    @Result(property = "userList",  //要封装的属性名称
            column = "id",  //根据哪个字段去查询目标表的数据
            javaType = List.class,  //要封装的实体类型
            many = @Many(select = "com.r.dao.UserDao.findUserById111")
           )
})
@Select("select * from jntm_role where id = #{id}")
public List<Role> findRoleById1(Integer id);

测试类:

@Test
public void findUserById111() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);

    List<User> userList = userDao.findUserById111();

    for (User user : userList) {
        System.out.println(user.toString());
    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}
其它:@One、@Many注解同时写一起

刚才的多对多例子,因为剩了一个一对一的属性,就试了试😂

UserDao:

/**
     * 根据id查询用户信息和角色名
     * 多对多结果集封装 @Many
     * @return
     */
@Results({
    @Result(id = true, property = "id", column = "id"),
    @Result(property = "userCode", column = "userCode"),
    @Result(property = "userName", column = "userName"),
    @Result(property = "address", column = "address"),
    @Result(property = "role",  //要封装的属性名称
            column = "userRole",  //根据哪个字段去查询目标表的数据
            javaType = Role.class,  //要封装的实体类型
            one = @One(select = "com.r.dao.RoleDao.findRoleById")
           ),
    @Result(property = "roleList",  //要封装的属性名称
            column = "userRole",  //根据哪个字段去查询目标表的数据
            javaType = List.class,  //要封装的实体类型
            many = @Many(select = "com.r.dao.RoleDao.findRoleById1")
           )
})
@Select("select * from jntm_user")
public List<User> findUserById111();

测试类:

@Test
public void findUserById111() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);

    List<User> userList = userDao.findUserById111();

    for (User user : userList) {
        System.out.println(user.getId()+"---"+user.getUserName());
        System.out.println("用户角色名称:" + user.getRole().getRoleName());

    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tuerlechat,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值