MyBatis映射文件相关属性

映射文件

增删改查

之前已经演示过查询操作,这里重点来说一下增删改操作,使用接口的形式来映射

public interface EmployeeDao {
    Employee getEmployeeById(Integer id);
    void addEmployee(Employee employee);
    void udpateEmployee(Employee employee);
    void deleteEmployee(Integer id);
}

增加一行数据

这里特别注意的地方是:sqlSessionFactory.openSession()默认设置的是不自动提交,所以在做完对数据表的操作之后要手动提交数据

    @Test
    public void test03(){
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            sqlSessionFactory = MyBatisTest.getSqlSessionFactory();
            sqlSession = sqlSessionFactory.openSession();
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            Employee employee = new Employee(null, "Make", "1", "make@123.com");
            mapper.addEmployee(employee);
            System.out.println(employee);
            sqlSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

insert语句是可以获取插入数据的返回值的,例如主键id是自增的,那么我们设置keyProperty=“id”,会自动将id值返回到对象中

在这里插入图片描述

    <insert id="addEmployee" useGeneratedKeys="true" keyProperty="id">
        insert into employee (last_name,gender,email) values (#{lastName},#{gender},#{email})
    </insert>

修改一条数据

    @Test
    public void test04(){
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            sqlSessionFactory = MyBatisTest.getSqlSessionFactory();
            sqlSession = sqlSessionFactory.openSession();
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            mapper.udpateEmployee(new Employee(5,"Jim","1","jim@123.com"));
            sqlSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }
    <update id="udpateEmployee">
        update employee set last_name = #{lastName} , gender = #{gender} , email = #{email} where id = #{id}
    </update>

删除一条数据

    @Test
    public void test05(){
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            sqlSessionFactory = MyBatisTest.getSqlSessionFactory();
            sqlSession = sqlSessionFactory.openSession(true);
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            mapper.deleteEmployee(7);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }
    <delete id="deleteEmployee">
        delete from employee where id = #{id}
    </delete>

参数处理

在给sql语句注入参数时,会有三种不同的情况,以下我们一一讲解

无参数注入

直接执行sql语句,这没什么好说的

单个参数注入

MyBatis不会对参数进行特殊处理,只需要使用#{参数名}即可获取参数

多个参数注入

MyBatis会对参数进行特殊处理,多个参数会被封装成一个map对象,调用时使用#{key}即可

​ key为param1,param2…或参数的索引

​ value为传入的参数值

这个方法非常不方便我们阅读sql语句,所以MyBatis也为我们提供了命名参数的说法,比如我现在要根据id和lastName查询数据

public interface EmployeeDao {
    //@Param("id"),括号中的值为#{}中的值
    Employee getEmployeeByIdAndName(@Param("id") Integer id,@Param("lastName") String lastName);
}

POJO

如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;
#{属性名}:取出传入的pojo的属性值

Map

如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map
#{key}:取出map中对应的值

TO
如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象

参数封装为Map的过程

来看一下源码,下面这段源码分别对无参数、单个参数、多个参数分别进行了处理

    public Object getNamedParams(Object[] args) {
        int paramCount = this.names.size();
		//如果参数为null直接返回
        if (args != null && paramCount != 0) {
			//如果是单个参数,且没有呗@param标注,arg[0]直接返回
            if (!this.hasParamAnnotation && paramCount == 1) {
                Object value = args[(Integer)this.names.firstKey()];
                return wrapToMapIfCollection(value, this.useActualParamName ? (String)this.names.get(0) : null);
            } else {
				//如果为多个参数或者参数呗@param标识
                Map<String, Object> param = new ParamMap();
                int i = 0;
				//遍历names集合
                for(Iterator var5 = this.names.entrySet().iterator(); var5.hasNext(); ++i) {
                    Entry<Integer, String> entry = (Entry)var5.next();
					//将数据存为key=下标,也就是取值的时候可以使用#{0},#{1}来表示所对应的值
                    param.put(entry.getValue(), args[(Integer)entry.getKey()]);
                    String genericParamName = "param" + (i + 1);
					//将key设置为"param" + (i + 1)的形式,可以是用#{param1},#{param2}来表示所对应的值
                    if (!this.names.containsValue(genericParamName)) {
                        param.put(genericParamName, args[(Integer)entry.getKey()]);
                    }
                }

                return param;
            }
        } else {
            return null;
        }
    }

#{}与${}的区别

两者都是用来获取map中的值或者pojo对象属性的值,通过一个例子来看一下区别,设置id的取值为${},lastname的取值为#{}

    <select id="getEmployeeByIdAndName" resultType="com.yellowstar.mybatis.bean.Employee">
        select * from employee where id = ${id} and last_name = #{lastName}
    </select>

日志输出的sql语句为

Preparing: select * from employee where id = 1 and last_name = ?
Parameters: Tom(String)

不难看出,#{}是以预编译的形式,将参数设置到sql语句中,防止sql注入,而${}是直接将值拼接到sql语句中会出现安全问题


select用法

返回List集合

接收数据的类型应为List的泛型类型

    <!--List<Employee> getEmployeeResultList(String name);-->
    <select id="getEmployeeResultList" resultType="com.yellowstar.mybatis.bean.Employee">
        select * from employee where last_name like #{name}
    </select>

返回map集合(返回值类型为map)

返回map集合时,如果我们设置返回值类型为map,则给我返回一个map集合,集合的值为key=value,其中key的值为列名,value值为那一列的数据

    <!--Map<Integer,Object> getEmployeeResultMap(String name);-->
    <select id="getEmployeeResultMap" resultType="map">
        select * from employee where id = #{id}
    </select>

返回map集合(返回值类型为实体类对象)

返回map集合,需要返回实体类对象,并且将主键值赋值给key

    @MapKey("id")  //作用:将id设为map集合的key值
    Map<Integer, Employee> getEmployeeLikeLastNameResultMap(String lastName);
    <!--Map<Integer,Employee> getEmployeeLikeLastNameResultMap(String lastName);-->
    <select id="getEmployeeLikeLastNameResultMap" resultType="com.yellowstar.mybatis.bean.Employee">
        select * from employee where last_name like #{name}
    </select>
resultMap

resultMap和resultType作用类似,且更加强大,两者不能得兼,使用一种即可

<!--Employee getEmployeeById(Integer id);-->
<!--resultMap
    id:唯一标识
    type:返回值类型的全类名
-->
<resultMap id="myResultMap" type="com.yellowstar.mybatis.bean.Employee">
    <!--id、result的作用是将数据库中的字段名与实体类的属性名对应起来-->
    <!--id用来表示主键-->
    <id column="id" property="id"/>
    <!--result表示普通列,如不设置则调用系统默认的值-->
    <result column="last_name" property="lastName"/>
    <result column="gender" property="gender"/>
    <result column="email" property="email"/>
</resultMap>
<select id="getEmployeeById" resultMap="myResultMap">
    select * from employee where id = #{id}
</select>

级联查询:多对一

上面讲到resultMap的作用是将数据库中的字段名与实体类的属性名相对应,有一种情况是我们的实体类中包含另一个对象的属性

比如员工类与部门类,每个员工通过部门id与部门类相关联

public class Employee {
    private Integer id;
    private String lastName;
    private String gender;
    private String email;
    private Department department;
}
public class Department {
    private Integer id;
    private String d_name;
}

数据库视图是这样构造的,其中员工表中的d_id与部门表中的id相关联

在这里插入图片描述

现在我们的需求是根据员工id查出员工信息以及他的部门信息

第一种方案:直接赋值

在查询sql语句时,通过左连接的方式将两张表关联起来

    <!--Employee getEmployeeAndDeptById(Integer id);-->
    <resultMap id="myResultMap2" type="com.yellowstar.mybatis.bean.Employee">
        <!--id用来表示主键-->
        <id column="id" property="id"/>
        <!--result表示普通列,如不设置则调用系统默认的值-->
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        <result column="dept_id" property="department.id"/>
        <result column="department_name" property="department.d_name"/>
    </resultMap>
    <select id="getEmployeeAndDeptById" resultMap="myResultMap2">
        SELECT e.id id,e.last_name,e.gender,e.email,e.d_id,d.id dept_id,d.department_name FROM `employee` e
        left JOIN `department` d
        on e.d_id = d.id
        where e.id = #{id}
    </select>

第二种方案:使用association属性

个人理解为一个resultMap的嵌套,与上面的方法大致相同

    <!--Employee getEmployeeAndDeptById(Integer id);-->
    <resultMap id="myResultMap3" type="com.yellowstar.mybatis.bean.Employee">
        <!--id用来表示主键-->
        <id column="id" property="id"/>
        <!--result表示普通列,如不设置则调用系统默认的值-->
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        <association property="department" javaType="com.yellowstar.mybatis.bean.Department">
            <id column="dept_id" property="id"/>
            <result column="department_name" property="d_name"></result>
        </association>
    </resultMap>
    <select id="getEmployeeAndDeptById" resultMap="myResultMap3">
        SELECT e.id id,e.last_name,e.gender,e.email,e.d_id,d.id dept_id,d.department_name FROM `employee` e
        left JOIN `department` d
        on e.d_id = d.id
        where e.id = #{id}
    </select>

第三种方案:分步查询&延迟加载

这里可以简化sql语句,以我们自己的思维方式来解决,需要查找员工所对应的部门,先找到员工,并且找到员工数据中的d_id值,在根据d_id去部门表中查询部门信息。而mybatis为我们准备了这种写法,就是分步查询

    <!--第一步:根据id查找员工信息-->
	<!--Employee getEmployeeById(Integer id);-->
    <resultMap id="getEmpStep" type="com.yellowstar.mybatis.bean.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        <!--
			select:下一步所调用的方法
			column:传递给下一步方法的参数
		-->
        <association property="department" select="com.yellowstar.mybatis.dao.DepartmentDao.getDepartmentById" column="d_id"></association>
    </resultMap>
    <select id="getEmployeePlusById" resultMap="getEmpStep">
        select * from employee where id = #{id}
    </select>
    <!--Department getDepartmentById(Integer id);-->
    <select id="getDepartmentById" resultType="com.yellowstar.mybatis.bean.Department">
        select id,department_name d_name from department where id = #{id}
    </select>

到这里其实个人觉得分步查询不如直接在sql语句中写好,因为分步查询与数据库进行了两次交互,mybatis为我们提供了延迟加载的机制,意思是我们用到此数据时再去发起sql语句进行查找,比如查找员工姓名,只会与数据库进行一次交互,不会发起第二条sql语句,我们需要在全局配置文件中设置

    <settings>
        <!--开启延时加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

级联查询:一对多

实际开发过程中,也可能遇到一对多的情况,比如要查找该部门下的所有员工,稍微修改一个部门类,添加员工集合

public class Department {
    private Integer id;
    private String d_name;
    private List<Employee> emps;
}

第一种方案:使用collection

    <!--Department getDeptfotAllEmp(Integer id);-->
    <resultMap id="getDeptforAllEmp" type="com.yellowstar.mybatis.bean.Department">
        <id column="did" property="id"/>
        <result column="department_name" property="d_name"/>
        <!--也相当于resultMap的嵌套,用法跟association类似-->
        <collection property="emps" ofType="com.yellowstar.mybatis.bean.Employee">
            <id column="id" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="gender" property="gender"/>
            <result column="email" property="email"/>
        </collection>
    </resultMap>
    <select id="getDeptforAllEmp" resultMap="getDeptforAllEmp">
        SELECT d.id did,d.department_name department_name, e.id id,e.last_name last_name,e.gender gender,e.email email FROM `department` d
        left join `employee` e
        on d.id = e.d_id
        where d.id = #{id}
    </select>

第二种方案:分步查询&延迟加载

    <!--Department getDeptByStep(Integer id);-->
    <resultMap id="getDeptByStep" type="com.yellowstar.mybatis.bean.Department">
        <id column="id" property="id"/>
        <result column="department_name" property="d_name"/>
        <collection property="emps" select="com.yellowstar.mybatis.dao.EmployeePlusDao.getEmployeeStep"
                    column="id"/>
    </resultMap>
    <select id="getDeptByStep" resultMap="getDeptByStep">
        select id,department_name from department where id = #{id}
    </select>
    <!--Employee getEmployeeStep(Integer id);-->
    <select id="getEmployeeStep" resultType="com.yellowstar.mybatis.bean.Employee">
        select * from employee where d_id = #{id}
    </select>

discriminator鉴别器

我个人将他理解为if判断器,通过一个例子来看一下,同样是使用上述的查找一个员工带出他的部门信息

要求:如果该员工性别为女(gender=0)带出她的部门信息,如果性别为男,不查找部门信息并且将他的email用姓名来赋值

    <!--Employee getEmployeeById(Integer id);-->
    <resultMap id="getEmpStep" type="com.yellowstar.mybatis.bean.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        <discriminator javaType="string" column="gender">
            <case value="0">
                <association property="department" select="com.yellowstar.mybatis.dao.DepartmentDao.getDepartmentById" column="d_id"></association>
            </case>
            <case value="1">
                <id column="id" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="gender" property="gender"/>
                <result column="last_name" property="email"/>
            </case>
        </discriminator>
    </resultMap>
    <select id="getEmployeePlusById" resultMap="getEmpStep">
        select * from employee where id = #{id}
    </select>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值