美文网首页
Apache MyBatis -- 模型层

Apache MyBatis -- 模型层

作者: saoraozhe3hao | 来源:发表于2018-08-18 22:49 被阅读0次

    历史:加拿大人Clinton Begin,2001年发布iBATIS,2004年提供给了Apache基金会,2010年改名为MyBatis
    Github:https://github.com/mybatis/mybatis-3
    文档:http://www.mybatis.org/mybatis-3/

    概念
    JDBC:Java DataBase Connectivity,JAVA的数据库连接API
    DAO:Data Access Objects,包含数据访问功能的JAVA对象
    POJO:Plain Ordinary Java Object,纯净普通的JAVA对象,即无继承父类无实现接口、不包含业务逻辑、含getter/setter的简单JAVA对象,用来映射数据库。
    ORM:Object Relational Mapping,对象关系映射,即JAVA对象和数据库表的映射
    ORM框架:提供ORM能力的框架,Hibernate和MyBatis都是ORM框架

    术语
    environment:目标数据库
    resource:配置文件
    namespace:SQL操作的汇总,即SQL操作interface

    与Hibernate的对比
    Hibernate根据映射关系自动生成SQL语句,MyBatis需要手写SQL语句。这样,使用MyBatis的工作量更大,但更具灵活性、可优化性

    IDEA 配置 MyBatis
    1、到官网或Maven中央仓库上查看可用版本,配置Maven依赖

    <dependency>
          <groupId>mysql</groupId>    <!-- mysql需要在配置文件里配置时区,default-time-zone='+08:00' -->
          <artifactId>mysql-connector-java</artifactId>
          <version>6.0.6</version>    <!-- 版本得跟mysql版本一致 -->
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    

    2、给IDEA添加插件 MyBatisCodeHelper,Settings -> Plugins -> 搜索MyBatisCodeHelper

    MyBatis应用的组成
    1、MyBatis 主配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <properties resource="db.properties"></properties>    <!-- 不用Maven也能引入properties文件 -->
    
        <settings>    <!-- 一些设置 -->
            <setting name ="cacheEnabled" value="true"/>
            <setting name="lazyLoadingEnabled" value="true"/>    <!-- 是否开启延迟加载 -->
            <!-- lazyLoadingEnabled为true时,aggressiveLazyLoading才有意义 -->
            <setting name="aggressiveLazyLoading" value="true"/>    <!-- 开启延迟加载的情况下,是否预先加载第二层 -->
        </settings>
    
        <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/db1" />   <!-- 指明仓库 -->
                    <property name="username" value="root" />
                    <property name="password" value="pass" />
                </dataSource>
            </environment>
        </environments>
        <mappers>    <!-- 映射配置文件列表 -->   
            <mapper resource="hogenMapper.xml"></mapper>
        </mappers>
    </configuration>
    ``
    
    2、作为 SQL参数的POJO
    public class CityParams {
        private String name;
        private String id;
        getter 和 setter
    }
    
    3、作为 SQL 结果的POJO
    ```java
    public class City {
        private Long id;
        private String cityName ;
        getter 和 setter
    }
    

    4、SQL操作接口

    public interface CityMapper {
        public City getCity(long id);   // SQL操作函数
        public List<City> findCityByBean(CityParams cityParams );  // 返回列表
        public void insertCity(CityParams cityParams);
        // 单参数,且该参数为非基本类型,则需要注解参数名,才能在 映射文件 中 引用该参数本身 ,否则只能引用它的成员
        public List<City> findCityByAnnotation(@Param("cityIds") String[] cityIds) ;
    }
    

    5、MyBatis映射配置文件,与SQL操作接口 组成映射器

    <?xml version="1.0" encoding="UTF-8"?>
    <mapper namespace="com.maven.hogen.CityMapper">    <!-- SQL操作接口 -->
        <cache/>    <!-- 本映射器开启二级缓存 -->
    
        <!-- 映射的双方分别为 SQL操作函数 和 SQL语句 -->
        <select id="getCity" parameterType="long" resultType="com.maven.hogen.City">    <!-- SQL操作函数的入参、返回类型 -->
            select id,name as cityName,countryCode from city where id= #{id}  <!-- select的字段得跟resultType的字段一致 -->
        </select>
    
        <!-- 多参数SQL 映射的 函数,其入参为POJO -->
        <select id="findCityByBean" parameterType="com.maven.hogen.CityParams" resultType="com.maven.hogen.City">
            select id,name as cityName,countryCode from city where name= #{name} and id=#{id}
        </select>
    
        <!-- 多参数SQL 映射的 函数,其入参为注解过的参数 -->
        <select id="findCityByAnnotation" resultType="com.maven.hogen.City">
            select id,name as cityName,countryCode from city where name= #{CityParams.name} and id=#{id}
        </select>
    
        <!-- 定义一个SQL结果和POJO之间的字段映射规则,供<select>使用 -->
        <resultMap id="cityMap" type="com.maven.hogen.City">
            <id property="id" column="id"/>
            <result property="cityName" column="city_name"/>
        </resultMap>
        <select id="getCity" parameterType="long" resultMap="cityMap">
            select id,city_name from city where id= #{id}
        </select>
    
        <!-- useGeneratedKeys表示插入后,将数据库自增ID回填给入参, keyProperty指明回填的POJO字段 -->
        <insert id="insertRole" parameterType="city" useGeneratedKeys="true" keyProperty="id">
            insert into city(role_name, note) values(#{cityName} , #{note})
        </ insert >
    
        <update id="updateRole"  parameterType="role">
            update t_role set role_name=#{roleName}, note= #{note} where id = #{id}
        </update>
        <delete id="deleteRole" parameterType="long">
            delete from t role where id = #{id}
        </delete>
    
         <!-- 一对一级联,即City包含一个Airport,查询City时带上Airport -->
         <resultMap type="com.maven.hogen.City" id="cityMap">
         <!-- 查询字段 与 pojo字段的对应关系,同名同类型字段自动对应 -->
             <id column="id" property="id"/> <!-- 字段映射,作为association参数的字段必须写,否则会为空 -->
             <!-- City中包含一个airport,通过getAirport来查询,column是外层SQL得到的列,是要给getAirport传的参数 -->
             <association property="airport" column="airport_id,airport_name" select=”com.maven.hogen.AirportMapper.getAirport”/>
            <!-- 基础类型的成员,除了用级联,也可以在主查询语句的SELECT子句中增加嵌套 或 连接查询来实现 -->
             <association property="carCount" column="id" select=”com.maven.hogen.CityMapper.getCarCount”/>
          </resultMap>
    
         <!-- 一对多级联,即City包含一个Street列表,查询City时带上Street列表 -->
         <resultMap type="com.maven.hogen.City" id="cityMap">
             <!-- City中包含一个streets,通过getStreet来查询一个street,column是外层SQL得到的列,是要给getStreet传的参数 -->
              <collection property="streets" column="street_id" select="com.maven.hogen.StreetMapper.getStreet" fetchType="lazy"/>
          </resultMap>
         
    </mapper>
    

    多对多关系 可以 拆分成两个一对多
    延迟加载:<association>和<resultMap>中含有fetchType="lazy",那么这个级联将延迟加载,即查询City时,不会马上带上airport,当调用city.getAirport()时,才发sql查询airport。fetchType设置会覆盖主配置文件中的lazyLoadingEnabled和aggressiveLazyLoading。原理:映射器返回的City实例,实际是City实例的代理对象,getAirport被修饰,sql查询得到aireport,再返回

    6、使用

    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSession;
    
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");    // 从resource目录,读入基础配置文件
    SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);  // 用建造者模式建造 SqlSession 工厂
    SqlSession sqlSession = SqlSessionFactory.openSession() ;  // 用工厂模式生产 SqlSession
    CityMapper cityMapper = sqlSession.getMapper(CityMapper.class) ;  // 用反射机制 生成 映射接口的子实例
    City city = cityMapper.getCity(1L);    // 调用接口的方法 相当于 SQL操作
    System.out.println(city.getCityName());
    sqlSession.close();
    

    缓存
    一级缓存:SqlSession 上的缓存,默认开启
    二级缓存:SqlSessionFactory上的缓存,需要二级缓存的POJO得可序列化,即实现java.io.Serializable
    给单个映射设置缓存规则

    <select flushCache="false" useCache="true"/>
    <insert flushCache="true"/>
    <update flushCache="true"/>
    <delete flushCache="true"/>
    

    动态SQL
    减少JAVA代码中的判断,减少SQL拼接

    <!-- if 结构  -->
    <selec>
        select id,city_name from city where 1=1
        <if test="cityName !=null and roleName !="">
            and city_name like concat('%', #{cityName}, '%')
        </ if>
    </select>
    
    <!-- if...else if...else 结构 -->
    <select>
        select id,city_name from city where 1=1
        <choose>
            <when test="id != null">
                and id = #{id}
            </when>
            <when test="cityName != null">
               and city_name like concat('%', #{cityName}, '%')
            </when>
            <otherwise>
                and countryCode is not null
            </otherwise>
        </choose>
    </select>
    
    <!-- 用<where>代替where 1=1 -->
    <select>
        select id,city_name from city
        <where>   <!-- 能把多余的and去掉 -->
            <if test="cityName != null">
                and city_name like concat('%', #{cityName}, '%')
            </if>
        </where>
    </select>
    
    <update>
        update city
        <set>  <!-- 能把多余的逗号去掉 -->
            <if test="cityName !=null">
                city_name= #{cityName},
            </if>
        </set>
        where id=#{id}
    </update>
    
    <!-- for 结构  -->
    <select>
        select * from city where city_name in
        <!-- collection是入参,open、separator、close用于拼接语句 -->
        <foreach item="cityName" index="index" collection="list" open="(" separator="," close=")">
            #{cityName}
        </foreach>
    < /select>
    

    SQL注入

    #{}是经过预编译的,是安全的;${}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入

    相关文章

      网友评论

          本文标题:Apache MyBatis -- 模型层

          本文链接:https://www.haomeiwen.com/subject/berqiftx.html