mybatis-sql映射文件

一、增删改查

  • mybatis允许增删改的方法直接定义返回值为Integer、Long、Boolean、void这些类型的,mybatis会自动帮我们封装返回值
  • sqlSessionFactory.openSession(),获取到的SqlSession不会自动提交数据,我们需要手动提交数据;sqlSessionFactory.openSession(true);===》自动提交

映射插入语句

  • 自增主键添加

mysql支持自增主键
  useGeneratedKeys="true";使用自增主键获取主键值策略
  keyProperty="id";指定对应的主键属性;

mybatis利用statement.getGenreatedKeys()获取到自增主键值后,将这个值封装给javaBean的哪个属性;不定义的话对象是获取不到id值的

    <insert id="addEmp" parameterType="com.mybatis.bean.Employee"
        useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
        insert into tbl_employee(last_name,email,gender) 
        values(#{lastName},#{email},#{gender})
    </insert>
  • 非自增主键添加

Oracle不支持自增,Oracle使用序列来模拟自增,每次插入的数据的主键是从序列中拿到的值;
  keyProperty:查出的主键值封装给javaBean的哪个属性
order="BEFORE":先运行selectKey查询id的sql;查出id值封装给javaBean的id属性
     resultType:查出的数据的返回值类型
    <insert id="addEmp" databaseId="oracle">
        <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
            select EMPLOYEES_SEQ.nextval from dual 
        </selectKey>
        
        insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
        values(#{id},#{lastName},#{email<!-- ,jdbcType=NULL -->}) 
    </insert>
  
order="AFTER":先运行插入的sql(从序列中取出新值作为id);再运行selectKey查询id的sql;
ps:如果同时插入多条数据,这样获取到的序列值不是当前插入的id
 <insert id="addEmp" databaseId="oracle">
        <selectKey keyProperty="id" order="AFTER" resultType="Integer">
         select EMPLOYEES_SEQ.currval from dual
        </selectKey>
       
        insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
        values(employees_seq.nextval,#{lastName},#{email}) 
    </insert>

映射删除语句

<delete id="deleteEmpById">
    delete from tbl_employee where id=#{id}
</delete>

映射更新语句

<update id="updateEmp">
        update tbl_employee 
        set last_name=#{lastName},email=#{email},gender=#{gender}
        where id=#{id}
</update>

映射查询语句

<select id="getEmpById" resultType="com.mybatis.bean.Employee">
        select * from tbl_employee where id = #{id}
</select>

代码

@Test
    public void test03() throws IOException{
        
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //获取到的SqlSession不会自动提交数据
        SqlSession openSession = sqlSessionFactory.openSession();
        
        try{
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            //测试添加
            Employee employee = new Employee(null, "jerry4",null, "1");
            mapper.addEmp(employee);
            System.out.println(employee.getId());
            
            //测试修改
            //Employee employee = new Employee(1, "Tom", "jerry@com", "0");
            //boolean updateEmp = mapper.updateEmp(employee);
            //System.out.println(updateEmp);
            //测试删除
            //mapper.deleteEmpById(2);
            //手动提交数据
            openSession.commit();
        }finally{
            openSession.close();
        }

二、参数处理

  • sql映射文件中的参数类型parameterType可以省略,mybatis会根据TypeHandle自动判断;个人认为如果写入的话能让开发者更清楚对应的是哪个JavaBean类或者哪种数据结构。
  • returnType定义别名或全类名

mybatis传入参数

1、单个参数:mybatis不会做特殊处理,#{参数名/任意名}:取出参数值。

2、多个参数:mybatis会做特殊处理。多个参数会被封装成 一个map,mybatis会帮我们把多个参数的key定义成param1...paramN

key:param1...paramN,或者参数的索引也可以
value:传入的参数值
#{}就是从map中获取指定的key的值;

  如果我们按照接口方法传入的参数名称去获取会出现以下异常

操作:
方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
取值:#{id},#{lastName}


异常:
org.apache.ibatis.binding.BindingException: 
Parameter 'id' not found. 
Available parameters are [1, 0, param1, param2]
View Code

解决方法有2种:

  • #{param1},#{param2}取值即可,但这种方式不能见名知意
  • 命名参数:明确指定封装参数时map的key;在方法参数前加上@Param("参数名"),这样key就会使用@Param注解指定的值
public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);

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

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

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

6、如果参数类型是Collection(List、Set)或者数组也会特殊处理。把传入的list或者数组封装在map中,

key命名:
Collection——(collection)
List——(list)
数组——(array)

取值方式
#{list[0]}

mybatis获取参数值

#{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
${}:取出的值直接拼装在sql语句中;会有安全问题;

  • 大多情况下,我们取参数的值都应该去使用#{};
  • 原生jdbc不支持占位符的地方我们就可以使用${}进行取值

#{}更多用法

参数的一些规则:javaType、 jdbcType、 mode(存储过程)、 numericScale、resultMap、 typeHandler、 jdbcTypeName、 expression(未来准备支持的功能)

ps:在我们传入数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错);这是因为mybatis在全局配置中对所有的null映射的是原生Jdbc的OTHER类型,而oracle不能识别JdbcType OTHER(无效的类型):

两种解决方案

1、#{email,jdbcType=OTHER};
2、修改全局配置jdbcTypeForNull属性的值<setting name="jdbcTypeForNull" value="NULL"/>

${}使用场景

比如分表、排序。。。;按照年份分表拆分
            select * from ${year}_salary where xxx;
            select * from tbl_employee order by ${f_name} ${order}

mybatis返回结果集

  • resultType指定期望结果集的全类名或别名,如果数据模型与数据库字段名称不匹配,可以开启驼峰命名或者在sql写别名的方式对应起来

以简单数据结构返回的这里就省略了;这里主要说下list、map以及指定相应泛型的方法。

如果返回的是一个list,要写集合中元素的类型,而不是list(resultType="javaBean的全类名/别名");我们想要的就是javaBean,只是结果有多条,mybatis会帮我们自动写入到一个list返回给我们

如果返回的是一条记录的map;key就是列名,值就是对应的值(resultType="map")

如果是多条记录封装一个map,比如Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javaBean,我们可以通过@MapKey告诉mybatis封装这个map的时候使用哪个属性作为map的key;而它的resultType="javaBean的全类名/别名"

@MapKey("id")
public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);

总结:returnType始终写的是我们想要mybatis把每一条记录封装成什么类型,无论是list还是多条记录的map,我们真正想要的是JavaBean的数据模型,mybatis会帮我们把这些数据封装成我们定义的方法返回类型

  • resultMap:自定义某个javaBean的封装规则

    type:自定义规则的java类型
    id:唯一id方便引用

1、简单查询

<resultMap type="com.mybatis.bean.Employee" id="MySimpleEmp">
        <!--指定主键列的封装规则
        id定义主键会底层有优化;
        column:指定哪一列
        property:指定对应的javaBean属性
          -->
        <id column="id" property="id"/>
        <!-- 定义普通列封装规则 -->
        <result column="last_name" property="lastName"/>
        <!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 -->
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
</resultMap>
    <select id="getEmpById"  resultMap="MySimpleEmp">
        select * from tbl_employee where id=#{id}
    </select>

2、联合查询(封装单对象)

  • 嵌套结果集的方式,级联属性封装结果集


<resultMap type="com.mybatis.bean.Employee" id="MyDifEmp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap>
  • 嵌套结果集的方式,使用association定义关联的单个对象的封装规则

<resultMap type="com.mybatis.bean.Employee" id="MyDifEmp2">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        
        <!--  association可以指定联合的javaBean对象
        property="dept":指定哪个属性是联合的对象
        javaType:指定这个属性对象的类型[不能省略]
        -->
        <association property="dept" javaType="com.mybatis.bean.Department">
            <id column="did" property="id"/>
            <result column="dept_name" property="departmentName"/>
        </association>
    </resultMap>
<select id="getEmpAndDept" resultMap="MyDifEmp">
  SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
  d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
  WHERE e.d_id=d.id AND e.id=#{id}
</select>
<select id="getEmpAndDept" resultMap="MyDifEmp">
  SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
  d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
  WHERE e.d_id=d.id AND e.id=#{id}
</select>
  • 使用association进行分步查询

<resultMap type="com.mybatis.bean.Employee" id="MyEmpByStep">
         <id column="id" property="id"/>
         <result column="last_name" property="lastName"/>
         <result column="email" property="email"/>
         <result column="gender" property="gender"/>
         <!-- association定义关联对象的封装规则
             select:表明当前属性是调用select指定的方法查出的结果(namespace+标识id)
             column:指定将哪一列的值传给这个方法作为传参的参数
          -->
         <association property="dept" 
             select="com.mybatis.dao.DepartmentMapper.getDeptById"
             column="d_id">
         </association>
</resultMap>
//引用MyEmpByStep,它会根据加载策略进行二次查询
<select id="getEmpByIdStep" resultMap="MyEmpByStep">
         select * from tbl_employee where id=#{id}
</select>

//dept部分 <select id="getDeptById" resultType="com.mybatis.bean.Department">   select id,dept_name departmentName from tbl_dept where id=#{id} </select>

3、联合查询(封装Collection)

  • 嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则
<resultMap type="com.mybatis.bean.Department" id="MyDept">
        <id column="did" property="id"/>
        <result column="dept_name" property="departmentName"/>
        <!-- 
            collection定义关联集合类型的属性的封装规则 
            ofType:指定集合里面元素的类型
        -->
        <collection property="emps" ofType="com.mybatis.bean.Employee">
            <!-- 定义这个集合中元素的封装规则 -->
            <id column="eid" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
        </collection>
    </resultMap>
<select id="getDeptByIdPlus" resultMap="MyDept">
        SELECT d.id did,d.dept_name dept_name,
                e.id eid,e.last_name last_name,e.email email,e.gender gender
        FROM tbl_dept d
        LEFT JOIN tbl_employee e
        ON d.id=e.d_id
        WHERE d.id=#{id}
</select>
  • 使用collection进行分段查询 

<resultMap type="com.mybatis.bean.Department" id="MyDeptStep">
        <id column="id" property="id"/>
        <id column="dept_name" property="departmentName"/>
        <collection property="emps" 
            select="com.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
            column="id"></collection>   
//如果需要多个查询条件的话,使用map进行传递column="{key1=column1,key2=column2}",其中key1是getEmpsByDeptId获取的参数名,column1是我们传递过去的属性值{deptId=id}
</resultMap>

<select id="getDeptByIdStep" resultMap="MyDeptStep">
  select id,dept_name from tbl_dept where id=#{id}
</select>

鉴别器

  可以使用discriminator判断某列的值,然后根据某列的值改变封装行为

     <resultMap type="com.mybatis.bean.Employee" id="MyEmpDis">
         <id column="id" property="id"/>
         <result column="last_name" property="lastName"/>
         <result column="email" property="email"/>
         <result column="gender" property="gender"/>
         <!-- column:指定判定的列名;javaType:列值对应的java类型  -->
         <discriminator javaType="string" column="gender">
             <!--  如果=0,查询出dept的信息  -->
             <case value="0" resultType="com.mybatis.bean.Employee">
                 <association property="dept" 
                     select="com.mybatis.dao.DepartmentMapper.getDeptById"
                     column="d_id">
                 </association>
             </case>
             <!--  如果=1,把last_name这一列的值赋值给email  -->
             <case value="1" resultType="com.mybatis.bean.Employee">
                 <id column="id" property="id"/>
                 <result column="last_name" property="lastName"/>
                 <result column="last_name" property="email"/>
                 <result column="gender" property="gender"/>
             </case>
         </discriminator>
     </resultMap>

延迟加载(按需加载)

  • 使用分步查询可以使用全局配置文件制定延迟加载策略
<!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/> 
  • 也可在collection或association里加入fetchType

fetchType="lazy"  - lazy:延迟  - eager:立即

 

posted @ 2020-08-01 19:25  edda_huang  阅读(140)  评论(0编辑  收藏  举报