• MyBatis 入门(一)


    1. MyBatis 概述

    1. MyBatis 是一个半自动化的持久层框架;
      • 核心SQL,开发人员可以进行优化;
      • SQL和Java编码分开,功能边界清晰,一个专注业务,一个专注数据;
    2. JDBC:
      • SQL 语句夹在Java代码块里,耦合度高,导致硬编码内伤;
      • 维护不易且实际开发需求中SQL是有变化,频繁修改的情况多见;
    3. Hibernate 和 JPA
      • 长难复杂SQL,对于Hibernate而言处理也不容易;
      • 内部自动生产的SQL,不容易做特殊优化;
      • 基于全映射的全自动框架,大量字段的POJO进行部分映射时,比较困难;从而导致数据库性能下降;

    2. MyBatis 入门程序搭建

    // 创建 Java Project
    
    // 1. 导入 jar 包(3个)
        /*
         * log4j-1.2.17(用来在控制台打印 SQL 语句)
         * mybatis-3.4.1
         * mysql-connector-java (SQL 驱动包)
         */
    
    // 2. 创建 Bean
    // cn.itcast.mybatis.bean.Employee.java
    public class Employee{
        private Integer id;
        private String lastName;
        private String email;
        // 以数字 0 表示男性, 1 表示女性
        private Integer gender;
    
        // getter 和 setter 略
    }
    
    // 3. 配置文件, 存放在 conf 文件夹下
    // 创建 Source Folder, 名称为 conf
    
    // log4j.xml
        (具体见"参考资料"中链接)
    
    // mybatis-config.xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	<environments default="development">
    		<environment id="development">
    			<transactionManager type="JDBC" />
    			<dataSource type="POOLED">
    				<property name="driver" value="com.mysql.jdbc.Driver" />
    				<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
    				<property name="username" value="root" />
    				<property name="password" value="root" />
    			</dataSource>
    		</environment>
    	</environments>
    
    	<!-- 将写好的SQL映射文件,一定要注册到全局配置文件中 -->
    	<mappers>
    		<mapper resource="EmployeeMapper.xml" />
    	</mappers>
    </configuration>
    
    
    // EmployeeMapper.xml
    // sql 映射文件
    <?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="cn.itcast.mybatis.EmployeeMapper">
    
      <!-- namespace: 命名空间, id: 表示唯一标识, resultType: 返回值类型 -->
      <select id="selectEmp" resultType="cn.itcast.mybatis.bean.Employee">
    
        <!-- 数据库中 last_name, Bean 类中 lastName, 以下相当于用别名查询 -->
        <!-- #{id} 表示从传递过来的参数中,获取id值 -->
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
      </select>
    </mapper>
    
    
    // 4. 编写测试类
    public class MyBatisTest{
    
        // 1. 根据mybatis的配置文件(全局配置文件),创建一个 SqlSessionFactory 对象;
    
        @Test
        public void test() throws IOException{
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resorces.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = 
                                            new SqlSessionFactoryBuilder().build(inputStream);
    
            // 2. 获取 SqlSession 实例, 使用该实例执行数据库的增删改查;
            //    一个sqlSession,就是代表和数据库的一次会话,用完需要关闭;
            //    sqlSession 是非线程安全的,每次使用都应该去获取新的对象;
            SqlSession openSession = sqlSessionFactory.openSession();
    
            try{
                // selectOne(String statement, Object parameter) 参数说明:
                //   statement: sql的唯一标识, 建议写法: 命名空间+id
                //   parameter: 执行 sql 要用的参数
                Employee employee = 
                        openSession.selectOne("cn.itcast.mybatis.EmployeeMapper.selectEmp",1);
                System.out.println(employee);
            }finally{
                openSession.close();
            }
        }
    }
    
    
    // 升级版本: 接口式编程
    // 使用接口,实现增删改查
    // 创建 cn.itcast.mybatis.dao.EmployeeMapper.java 接口
    public interface EmployeeMapper{
    
        // 按id查询
        public Employee getEmpById(Integer id);
    }
    
    // 修改 EmployeeMapper.xml
    // sql 映射文件
    <?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="cn.itcast.mybatis.dao.EmployeeMapper">
    
      <!--
      namespace: 命名空间,指定为接口的全类名;
      id: 表示唯一标识,接口中的方法名;
      resultType: 返回值类型
      -->
    
      <select id="getEmpById" resultType="cn.itcast.mybatis.bean.Employee">
    
        <!-- 数据库中 last_name, Bean 类中 lastName, 以下相当于用别名查询 -->
        <!-- #{id} 表示从传递过来的参数中,获取id值 -->
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
      </select>
    </mapper>
    
    // 修改测试类
    public class MyBatisTest{
    
        // 获取 sqlSessionFactory 对象的方法
        public SqlSessionFactory getSqlSessionFactory() throws IOException{
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            return new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        @Test
        public test02() throws IOException{
            // 1. 获取 sqlSessionFactory 对象
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    
            // 2. 获取 SqlSession 实例
            SqlSession openSession = sqlSessionFactory.openSession();
    
            try{
                // 3. 获取接口的实现类对象
                //  mybatis 会为接口自动创建一个代理对象, 代理对象去执行增删改查方法
                EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    
                // 调用接口实现类的方法
                Employee employee = mapper.getEmpById(1);
                System.out.println(employee);
            }finally{
                // 4. 关闭 SqlSession
                openSession.close();
            }
        }
    }
    

    3. MyBatis 全局配置文件

    3.1 常用标签介绍

    • <properties>: 引入外部 properties 配置文件的内容;
      • resource属性: 引入类路径下的资源;
      • url属性: 引入网络路径或者磁盘路径下的资源;
    • <settings>: 包含了很多重要的设置项
    • <typeAliases>: 别名处理器,可以给 java 类型起别名,方便使用;
    • <typeHandlers>: 类型处理器, 处理数据库类型与Java类型的转换;
    • <plugins>
    • <environments>: mybatis 可以配置多种环境, default 的值对应<environment>中的 id 值;
    • <databaseIdProvider>: 设置数据库厂商;
    • <mappers>: 将sql映射文件注册到全局配置文件中;
    // mybatis-config.xml 配置文件
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <properties resource="dbconfig.properties"></properties>
    
        <!-- 是否开启驼峰命名:即从数据库列名"a_column"到Java属性名 "aColumn" 的类似映射 -->
        <settings>
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    
        <!-- typeAliase, 别名处理器, 别名不区分大小写 -->
        <typeAliases>
            <!-- 默认别名就是类名小写: employee; 也可以使用 alias 指定新的别名 -->
            <typeAlias type="cn.itcast.mybatis.bean.Employee"/>
    
            <!-- package: 为某个包下的所有类批量起别名
                     name: 指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写))
    
                批量起别名的情况下, 使用 @Alias 注解为某个类型指定新的别名;
            -->
            <package name="cn.itcast.mybatis.bean"/>
        </typeAliases>
    
    	<environments default="development">
    		<environment id="development">
    			<transactionManager type="JDBC" />
    			<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>
    
    	<!-- 将写好的SQL映射文件,一定要注册到全局配置文件中
                注册配置文件:
                    resource: 引入类路径下的sql映射文件;
                    url: 引用网络路径或者磁盘路径下的sql映射文件;
                也可以注册接口:
                    class: 注册接口
                        1. 有 sql 映射文件,映射文件名必须和接口同名,并且放在与接口同一目录下;
                        2. 没有 sql 映射文件,所有的 sql 都是利用注解写在接口上;
                备注:
                    比较重要,复杂的 Dao 接口,使用 sql 映射文件;
                    简单的Dao接口为了开发方便,可以使用注解;
        -->
    	<mappers>
    		<mapper resource="EmployeeMapper.xml" />
            <mapper class="cn.itcast.mybatis.bean.EmployeeMapper"/>
    	</mappers>
    </configuration>
    
    
    // dbconfig.properties 配置文件
    jdbc.driver=com.mysql.jdbc.driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.username=root
    jdbc.password=root
    

    4. MyBatis 映射文件

    // 映射增删改查语句
    
    // EmployeeMapper.java 接口
    public interface EmployeeMapper{
    
        // 单个参数
        public Employee getEmpById(Integer id);
    
        public void addEmp(Employee employee);
    
        public void updateEmp(Employee employee);
    
        public void deleteEmpById(Integer id);
    
        // 备注:
        //    MyBatis 允许增删改直接定义以下返回值: Integer, Long, Boolean, void
        //    表示增删改影响的行数, 如果行数大于0, Boolean 值为 true;
        // 例如: public boolean updateEmp(Employee employee);
    }
    
    // EmployeeMapper.xml 配置文件
    <mapper namespace="cn.itcast.mybatis.dao.EmployeeMapper">
    
    <!-- 查询方法 -->
    <select id="getEmpById" resultType="cn.itcast.mybatis.bean.Employee">
        select * from tbl_employee where id="#{id}"
    </select>
    
    <!-- 添加方法
            自增主键值的获取: MyBatis 也是利用 statement.getGeneratedKeys(); 不过,需要配置
            useGeneratedKeys="true": 表示使用自增主键获取主键值策略
            keyProperty: 指定对应的主键属性,也就是MyBatis获取到主键值以后,将这个值封装给 JavaBean 的哪个属性
    -->
    <insert id="addEmp" useGeneratedKeys="true" keyProperty="id">
        insert into tbl_employee(last_name,email,gender)
        values(#{lastName},#{email},#{gender})
    </insert>
    
    <!--
        Oracle 不支持自增; Oracle 使用序列来模拟自增;
        每次插入的数据的主键,是从序列中拿到的值,
        Oracle 数据库中获取主键的配置:
    -->
        <insert id="addEmp" databaseId="oracle">
            <!--
                keyProperty: 查出的主键值封装给 JavaBean 的哪个属性
                order="BEFORE": 当前sql在插入sql之前运行
                resultType: 查询出数据的返回值类型
            -->
            <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
                <!-- 查询主键的sql语句 -->
                select EMPLOYEES_SEQ.nextval from dual
            </selectKey>
    
            <!-- 插入数据时的主键,是从序列中拿到的 -->
            insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
            values(#{id},#{lastName},#{email})
        </insert>
    
    
    <!-- 更新方法 -->
    <update id="updateEmp">
        update tbl_employee
            set last_name=#{lastName},email=#{email},gender=#{gender}
            where id=#{id}
    </update>
    
    <!-- 删除方法 -->
    <delete id="deleteEmpById">
        delete from tbl_employee where id=#{id}
    </delete>
    
    </mapper>
    
    // 编写测试类
    public class MyBatisTest{
        // 1. 获取 SqlSessionFactory 方法(同上)
    
        // 2. 测试方法
        @Test
        public void test01() throws IOException{
            // 1. 获取 SqlSessionFactory 对象
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    
            // 2. 获取 SqlSession 实例
            //       sqlSessionFactory.openSession();  该实例需要手动提交数据
            //       sqlSessionFactory.openSession(true);   该实例可以自动提交数据
            SqlSession openSession = sqlSessionFactory.openSession();
    
            try{
                // 3. 获取接口的实现类对象
                EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    
                // 添加方法
                Employee employee = new Employee(null,"zhangsan","zhangsan@163.com","1");
                mapper.addEmp(employee);
                // 输出主键值
                System.out.println(employee.getId());
    
                // 更新方法
                Employee employee = new Employee(1,"lisi","lisi@163.com","1");
                mapper.updateEmp(employee);
    
                // 删除方法
                mapper.deleteEmpById(2);
    
                // 4. 手动提交
                openSession.commit();
            }finally{
                // 5. 关闭资源
                openSession.close();
            }
        }
    }
    
    

    4.1 MyBatis 映射文件的参数处理

    // 示例: 查询方法中带有多个参数
    
    // EmployeeMapper.java 接口
    public interface EmployeeMapper{
    
        // 多个参数
        public Employee getEmpByIdAndLastName(Integer id, String lastName);
    }
    
    
    // EmployeeMapper.xml 配置文件
    <mapper namespace="cn.itcast.mybatis.dao.EmployeeMapper">
    
    <!-- 查询方法(多个参数)
         出现异常:  org.apache.ibatis.binding.BindingException:
                   Parameter 'id' not found. Available parameters are [0, 1, param1, param2]
    -->
    <select id="getEmpByIdAndLastName" resultType="cn.itcast.mybatis.bean.Employee">
        select * from tbl_employee where id=#{id} and last_name=#{lastName}
    </select>
    
    <!-- 查询方法(多个参数)
            多个参数: mybatis 会做特殊处理
            多个参数会被封装成一个 map,
                    其中 key: param1,...paramN, 或者参数的索引
                        value: 传入的参数值
            #{}就是从 map 中获取指定的key值
    -->
    <select id="getEmpByIdAndLastName" resultType="cn.itcast.mybatis.bean.Employee">
        select * from tbl_employee where id=#{param1} and last_name=#{param2}
    </select>
    
    <!-- 查询方法(多个参数)
        也可以使用命名参数的方法: 在封装参数时,明确指定map中的key值:
        接口的写法:
        public Employee getEmpByIdAndLastName(@Param("id")Integer id, 
                                                                                @Param("lastName")String lastName)
    -->
    <select id="getEmpByIdAndLastName" resultType="cn.itcast.mybatis.bean.Employee">
        select * from tbl_employee where id=#{id} and last_name=#{lastName}
    </select>
    
    <!-- 查询方法(多个参数)
        POJO:
            如果多个参数正好是业务逻辑的数据模型,可以直接传入POJO;
            #{属性名}: 取出传入的POJO类的属性值
    
        Map:
            如果多个参数不是业务模型中的数据,没有对应的POJO,不经常使用, 为了方便,也可以传入Map
            #{key}: 取出map中对应的值
            此时, 接口中的方法:
            public Employee getEmpByMap(Map<String, Object> map);
    
        TO:
            如果多个参数不是业务模型的数据,但是经常要使用,推荐编写一个 TO(Tranfer Object)数据传输对象
    
        特别注意: 如果是 Collection(List,Set)类型或者是数组,mybatis 也会特殊处理,把传入的list或
                者数组封装到map中,
                其中,key: Collection(collection), 如果是 List, 还可以使用 key(list),数组(array)
        public Employee getEmpById(List<Integer> ids);
             取出list集合中第一个id的值: #{list[0]}
    -->
    <select id="getEmpByMap" resultType="cn.itcast.mybatis.bean.Employee">
        select * from tbl_employee where id = #{id} and last_name=#{lastName}
    </select>
    
    
    </mapper>
    
    
    // 编写测试类
    public class MyBatisTest{
        // 1. 获取 SqlSessionFactory 方法(同上)
    
        // 2. 测试方法
        @Test
        public void test01() throws IOException{
            // 1. 获取 SqlSessionFactory 对象
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    
            // 2. 获取 SqlSession 实例
            //       sqlSessionFactory.openSession();  该实例需要手动提交数据
            //       sqlSessionFactory.openSession(true);   该实例可以自动提交数据
            SqlSession openSession = sqlSessionFactory.openSession();
    
            try{
                // 3. 获取接口的实现类对象
                EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    
                // 4. 查询数据
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("id",1);
                map.put("lastName","zhangsan");
                Employee employee = mapper.getEmpByMap(map);
                System.out.println(employee);
    
            }finally{
                // 5. 关闭资源
                openSession.close();
            }
        }
    }
    

    4.2 参数值的获取

    1. #{}: 可以获取map中的值或者pojo对象属性的值;
    2. ${}: 也可以获取map中的值或者pojo对象属性的值;
    3. 区别:
      • #{}: 是以预编译的形式,将参数设置到sql语句中, PreparedStatement: 可以防止 Sql 注入;
      • ${}: 取出的值直接拼装在sql语句中, 会有安全问题;
      • 大多情况下,应该使用 #{};

    4.3 #{}更丰富的用法

    • 参数位置支持的属性: javaType, jdbcType, mode(存储过程), numericScale, resultMap, typeHandler,
      jdbcTypeName;
    • 实际上,通常被设置的是: 可能为空的列名指定 jdbcType;因为mybatis对所有null都映射的是原生Jdbc的 OTHER;
      Oracle 数据库不能正确识别,会报错;
    • #{email,jdbcType=NULL}表示email列为null时,该列的类型为原生Jdbc的 NULL类型;

    参考资料

  • 相关阅读:
    ORA01034:ORACLE not available 问题的解决方法
    利用Bulk Insert将Excel中的大批量数据入库
    【Hibernate】*.hbm.xml配置
    lib和dll文件的区别和联系
    oracle ,mysql总date的比较
    C++ Primer 4 CPP Note 1.5 类的简介
    C++ Primer 4 CPP Note 1.4 控制结构
    未找到方法: Dispose System.IO.Stream
    pragma comment的使用
    C++ Primer 4 CPP Note 2.1 基本内置类型
  • 原文地址:https://www.cnblogs.com/linkworld/p/7787490.html
Copyright © 2020-2023  润新知