• (三)Mybatis------引入Mapper接口以及传入各种参数类型


    (三)Mybatis------引入Mapper接口

    引入Mapper接口并测试,新建接口。

    package dao;
    
    import POJO.ACicpTest1;
    
    //这个接口只是为了,更加方便上层代码调用Mybatis的具体功能
    // ACicpTest1Dao的路径和文件名,要和对应xml文件中的namespace一致
    // 方法名要和xml文件中sql的id一致,xml中id只能存在一个,因此接口中的方法不能重载
    
    
    public interface ACicpTest1Dao {
    
        public ACicpTest1 findOneById(String requestNo);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    新建测试类:

    import POJO.ACicpTest1;
    import dao.ACicpTest1Dao;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.IOException;
    
    public class MybatisTest {
    
        private SqlSession sqlSession;
    
    
        // junit会在每一个@Test方法前执行@Before方法
        @Before
        public void init() throws IOException {
    
    //        1.使用Mybatis的Resources类读取Mybatis全局配置文件
    //        InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
    //        2.使用InputStream创建sqlSessionFactoryBuilder对象
    //        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    //        3.调用builder对象的build方法创建SqlSessionFactory对象
    //        SqlSessionFactory build = builder.build(stream);
    //        4.通过SqlSessionFactory对象开启一个从Java程序到数据库的会话
    //        SqlSession sqlSession = build.openSession();
            //5.在通过SqlSession对象找到Mapper配置文件中可以执行的sql语句
            //两个参数,分别是statement、parameter
            // statement参数格式:Mapper配置文件namespace属性.SQL标签的id属性
            //parameter参数;给SQL语句传入的参数
    
             sqlSession = new SqlSessionFactoryBuilder().
                    build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();
        }
    
        @Test
        public void testMapperInterFace(){
            //根据ACicpTest1Dao接口的class对象获取Mapper接口类型的对象
            ACicpTest1Dao mapper = sqlSession.getMapper(ACicpTest1Dao.class);
            ACicpTest1 s = mapper.findOneById("40978");
            System.out.println(s);
    
        }
    
        @After
        public void clear(){
            sqlSession.commit();
            sqlSession.close();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    Mysql插入insert方法、删除delete、更新update时,会返回受影响的行数。

    <insert id="insertById">
            <!-- 本质上#{requestNo}、#{loancurrentstatus}还是走了实体类的get、set方法,通过打断点可以看到-->
            insert into a_cicp_test_1 values  (#{requestNo},#{loancurrentstatus})
           </insert>
    
    • 1
    • 2
    • 3
    • 4

    #{}会被换成?占位符

    ${}不会被换成?占位符,而是会根据?占位符进行字符串拼接,这样会引起SQL注入的问题,存在安全问题
    至于为什么#{}能够防止SQL注入
    原因:#{}匹配的是一个占位符,相当于 JDBC 中的一个?,底层采用的是 PreparedStatement,会对一些敏感字符进行过滤,编译过后会对传递的值加上双引号,因此可以防止 SQL 注入问题。

    注意:如果表名是动态的,需要从参数中传进来,此时只能用拼接,不能用#{},因为数据库不允许表名位置使用?占位符。
    写、更新操作:返回的是受影响的条数。

    传入参数类型分为基本类型和复杂类型

    简单类型:一个值的参数,int、String、Double等等
    负载类型:实体类、集合、数组类型、复合类型,Student、Lits、int[]、List[Student]

    传入对象

    
    int insertEmployee(Employee employee);
    
    <insert id="insertEmployee">
        insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
    </insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当传入的是对象时,Mybatis会根据#{}中传入的数据,加工成getXxx()方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}这个位置。

    传入多个简单的数据类型

    
    int updateEmployee(@Param("empId") Integer empId,@Param("empSalary") Double empSalary);
    
     <update id="updateEmployee">
            update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}
        </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当传入多个数据类型时,使用@Param(”xxx“),其中的字段名要和SQL中的字段名一致。

    传入Map

      Map<String, Object> paramMap = new HashMap<>();
        
        paramMap.put("id", 1);
        paramMap.put("name", "zhangsan");
         paramMap.put("age", 5);
    
    int updateEmployeeByMap(Map<String, Object> paramMap);
    
    
        <update id="updateEmployeeByMap">
            update t_emp set name=#{name},age=#{age} where id=#{id}
        </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    传入map时,#{}中写map中对应的key值即可。

    出参各种类型

    返回参数时对象

    <select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">
        select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}
    </select>
    
    • 1
    • 2
    • 3

    如果配置文件中没有做字段映射时,需要给查询出的字段起别名,使字段别名和对象中的属性值一致。

    增加全局配置自动识别对应关系

    要求比较高,格式必须为:数据库字段命名为student_id,而属性命名为studentId,如果开发过程中规定好了,并且都能遵守,就可以用,否则慎用。

    <!-- 在全局范围内对Mybatis进行配置 -->
    <settings>
        <!-- 具体配置 -->
        <!-- 从org.apache.ibatis.session.Configuration类中可以查看能使用的配置项 -->
        <!-- 将mapUnderscoreToCamelCase属性配置为true,表示开启自动映射驼峰式命名规则 -->
        <!-- 规则要求数据库表字段命名方式:单词_单词 -->
        <!-- 规则要求Java实体类属性名命名方式:首字母小写的驼峰式命名 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    返回Map类型

    Map<String,Object> selectEmpNameAndMaxSalary(); 
    
    <!-- 返回工资最高的员工的姓名和他的工资 -->
    <select id="selectEmpNameAndMaxSalary" resultType="map">
            SELECT
                emp_name 员工姓名,
                emp_salary 员工工资,
                (SELECT AVG(emp_salary) FROM t_emp) 部门平均工资
            FROM t_emp WHERE emp_salary=(
                SELECT MAX(emp_salary) FROM t_emp
            )
    </select>
    
    Map<String, Object> resultMap = employeeMapper.selectEmpNameAndMaxSalary();
        
            Set<Map.Entry<String, Object>> entrySet = resultMap.entrySet();
        
            for (Map.Entry<String, Object> entry : entrySet) {
                String key = entry.getKey();
                Object value = entry.getValue();
                System.out.println(key + "=" + value);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    返回Map类型时,最好是不能封装到一个对象中,如果能封装到一个对象中,则使用对象返回,其中字段名作为key,获取值作为value,循环取值。

    设置自增主键

    比如:规则引擎中,规则调用日志表,和规则触发表,此时规则触发表保存时,需要有外键关联到规则调用日志表,才能够关联查询到,该笔数据触发了哪些规则。
    此时在保存规则调用日志数据时就需要新增useGeneratedKeys属性设为true,开启自增主键。keyProperty代表着将自增值赋给类的属性,但并不是自增主键设置为返回值,而是传入的对象中,该字段会赋值,使用时通过get属性获得自增主键值

    <!-- int insertEmployee(Employee employee); -->
    <!-- useGeneratedKeys属性字面意思就是“使用生成的主键” -->
    <!-- keyProperty属性可以指定主键在实体类对象中对应的属性名,Mybatis会将拿到的主键值存入这个属性 -->
    <insert id="insertEmployee" useGeneratedKeys="true" keyProperty="empId">
        insert into t_emp(emp_name,emp_salary)
        values(#{empName},#{empSalary})
    </insert>
    
     employeeMapper.insertEmployee(employee);
        //获取自增主键。
     System.out.println("employee.getEmpId() = " + employee.getEmpId());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Mybatis是将自增主键的值设置到实体类对象中,而不是以Mapper接口方法返回值的形式返回。

    对于不支持自增主键的数据库,比如oracle

    写法1:

    <insert id="insertEmployee" 
            parameterType="com.atguigu.mybatis.beans.Employee"  
                databaseId="oracle">
            <selectKey order="BEFORE" keyProperty="id" 
                                           resultType="integer">
                select employee_seq.nextval from dual 
            </selectKey>    
            insert into orcl_employee(id,last_name,email,gender) values(#{id},#{lastName},#{email},#{gender})
    </insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    写法2:

    
    <insert id="insertEmployee" 
            parameterType="com.atguigu.mybatis.beans.Employee"  
                databaseId="oracle">
            <selectKey order="AFTER" keyProperty="id" 
                                             resultType="integer">
                select employee_seq.currval from dual 
            </selectKey>    
        insert into orcl_employee(id,last_name,email,gender) values(employee_seq.nextval,#{lastName},#{email},#{gender})
    </insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用

    使用resultMap标签,定义类、和数据表之前的对应关系

    此时返回值类型就不能用resultType,而使用resultMap,并且值为resultMap标签中的id值

    <!-- 专门声明一个resultMap设定column到property之间的对应关系 -->
    <resultMap id="selectEmployeeByRMResultMap" type="com.atguigu.mybatis.entity.Employee">
        
        <!-- 使用id标签设置主键列和主键属性之间的对应关系 -->
        <!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 -->
        <id column="emp_id" property="empId"/>
        
        <!-- 使用result标签设置普通字段和Java实体类属性之间的关系 -->
        <result column="emp_name" property="empName"/>
        <result column="emp_salary" property="empSalary"/>
    </resultMap>
        
    <!-- Employee selectEmployeeByRM(Integer empId); -->
    <select id="selectEmployeeByRM" resultMap="selectEmployeeByRMResultMap">
        select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    Java8实战-总结28
    16. Python 比较运算
    线段树以及使用
    扒一扒Nacos、OpenFeign、Ribbon、loadbalancer组件协调工作的原理
    零信任迈入2.0时代
    Curriculum Vitae;CV
    你听说过OTA吗?
    接口测试之深入理解HTTPS
    新版AndroidStudio的Gradle窗口显示task list not built 问题解决
    【Visual Leak Detector】配置项 ForceIncludeModules
  • 原文地址:https://blog.csdn.net/cz_chen_zhuo/article/details/125479819