Mybatis

Mybatis框架

框架:

1. 什么是框架:
    1. 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。
    2. 简而言之,框架其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。
2. 框架解决的问题
    1. 因此应该将应用自身的设计和具体的实现技术解耦。这样,软件企业的研发将集中在应用的设计上,而不是具体的技术实现,技术实现是应用的底层支撑,它不应该直接对应用产生影响
    * 框架一般处在低层应用平台(如 J2EE)和高层业务逻辑之间的中间层。

3. 软件开发分层重要性
    * 框架的重要性在于它实现了部分功能,并且能够很好的将低层应用平台和高层业务逻辑进行了缓和。为了实现软件工程中的“高内聚、低耦合”。把问题划分开来各个解决,易于控制,易于延展,易于分配资源。我们常见的MVC 软件设计思想就是很好的分层思想。
4. 常见的开发框架:
    * MyBatis
        * 解决数据的持久化问题的框架
    * spring MVC
        * 解决web层问题的MVC框架 
    * Spring框架
        * 解决技术整合问题的框架爱

MyBatis基本概念

1. 什么是MyBatis
    1. 概述:mybatis是一个持久层框架,用java编写的。它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程。它使用了ORM思想实现了结果集的封装。
    2. 详解:

    * mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
    * mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。

2. 有什么用
    * 采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。
3.ORM:
    * Object Relation Mapping 对象关系映射
    * 简单的说就是把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表
4. jdbc回顾:
    1. 加载数据库驱动
    2. 通过驱动管理类获取数据库连接
    3. 定义SQL语句使用? 占位符
    4. 获取预处理的Statement(preparestatement)
    5. 向数据库发出sql执行查询,查询出结果集
    6. 遍历查询结果集
    7. 释放资源
    * jdbc问题:
        1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
        2. Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java代码。
        3. 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
        4. 对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便。

MyBatis

1. mybatis的入门
    1. mybatis的环境搭建
        1. 第一步: 创建maven工程并导入坐标
        2. 创建实体类和dao的接口
        3. 创建Mybatis的主配置文件:SqlMapConfig.xml
        4. 创建映射配置文件: IUserDao.xml
    2. 搭建环境的注意事项:
        1. 创建IUserDao.xml 和IUserDao.java时名称是为了和我们之前的知识保持一致。 
            * 在Mybatis中它把持久层的接口名称和映射文件也叫做:Mapper
            * 所以IUserDao和IUserMapper是一样的
        2. 在idea中创建目录的时候,它和包是不一样的
            * 包在创建时: com.itheima.dao它是三级结构
            * 目录在创建时:com.itheima.Mapper是一级目录
        3. mybatis的映射配置文件位置必须和dao接口的包结构相同
        4. 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
        5. 映射配置文件的操作配置(select),id 属性的取值必须是dao接口的方法名
2. 我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式。不管使用XML还是注解配置。但是Mybatis它是支持写dao实现类的。
3. 编写测试mybatis的环境是否搭建好  步骤:
    1. 读取配置文件
    2. 创建SqlSessioFactory的构建者对象
    3. 使用构建者创建工厂对象SqlSessionFactory
    4. 使用SqlSessionFactory生产SqlSession对象
    5. 使用SqlSession创建dao接口的代理对象
    6. 使用代理对象执行查询所有方法
    7. 释放资源
4.URL属性:
    * 是要求按照URL的写法来写地址
    * URL: Uniform Reource Locator 统一资源定位符。它是可以唯一标志一个资源的位置
    * 它的写法:
        http://localhost:8080/mybatisserver/demolServlet
        协议   主机       端口       URI
    * URI: Uniform Resource Identifier 统一资源标志符。它是在应用中可以唯一定位一个资源的
5.SqlMapConfig.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属性: 常用的
                用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。
            url属性:
                是要求按照Url的写法来写地址
                URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。
                它的写法:
                    http://localhost:8080/mybatisserver/demo1Servlet
                    协议      主机     端口       URI
    
                URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。
        -->
        <properties url="file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">
           <!-- <property name="driver" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"></property>
            <property name="username" value="root"></property>
            <property name="password" value="1234"></property>-->
        </properties>
    
        <!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
        <typeAliases>
            <!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写 
            <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
    
            <!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
            <package name="com.itheima.domain"></package>
        </typeAliases>
    
        <!--配置环境-->
        <environments default="mysql">
            <!-- 配置mysql的环境-->
            <environment id="mysql">
                <!-- 配置事务 -->
                <transactionManager type="JDBC"></transactionManager>
    
                <!--配置连接池-->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"></property>
                    <property name="url" value="${jdbc.url}"></property>
                    <property name="username" value="${jdbc.username}"></property>
                    <property name="password" value="${jdbc.password}"></property>
                </dataSource>
            </environment>
        </environments>
        <!-- 配置映射文件的位置 -->
        <mappers>
            <!--<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>-->
            <!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了 -->
            <package name="com.itheima.dao"></package>
        </mappers>
    </configuration>
6. resultMap 在返回结果的时候,有两种:一种是 resultType ,一种是resultMap
    1. resultMap 可以用于在数据库的名称和自己定义的实体类的名称不完全一致的时候,这时候就可以使用resultMap 返回
    2. 使用的时候要先配置: 建立USer实体和数据库表的对应关系。 type 属性: 指定实体类的全限定类名;id属性: 给定一个唯一标志,是给查询select标签使用的

                        <resultMap id="userMap" type="user">
                                <id property="id" column="id"></id>
                                <result property="username" column="username"></result>
                                <result property="address" column="address"></result>
                                <result property="birthday" column="birthday"></result>
                                <result property="sex" column="sex"></result>
                            </resultMap>
            * id 标签: 用于制定主键字段
            * result标签: 用于指定非主键字段
            * column属性 : 用于指定数据库列名
            * property属性: 用于指定实体类属性名称

mybatis 中的动态Sql语句

1. if 标签的使用:
    例子:
            <select id="findUserByCondition" resultMap="userMap" parameterType="user">
            
                    select * from user where 1=1
                    <if test="username != null">
                        and username=#{username}
                    </if>
                    <if test="sex != null">
                        and sex=#{sex}
                    </if>
            
                </select>
2. where 标签: 将if标签嵌套到where标签里面。 如果使用where 标签就不用加入 "where 1=1"这个永远为真的条件
3. 抽取重复sql语句:
        <sql id ="defaultUser">
            select * from user
        </sql> 
    * 使用的时候
        <include refid="defultUser"></include>

Mybatis 中的事务:

1. 什么是事务
2. 事务的四大特性:ACID
3. 不考虑隔离性会产生的3个问题
4. 解决方法: 四种隔离级别
5. 它是通过SQLSession对象的commit方法和rollback方法实现事务的提交和回滚

MyBatis 中的多表查询(使用的是xml文件配置的方式)

1. 表之间的关系:
    1. 一对多
    2. 多对一
    3. 一对一
    4. 多对多
2. mybatis 把多对一看成了一对一
3. MyBatista中的多表查询示例: 用户和账户 (一对多与多对一):重要一点: mybatis中多对一就是一对一
    * 一个用户可以有多个账户
    * 一个账户只能属于一个用户(多个账户也可以属于同一个用户)
    1. 实现步骤
        1. 建立两张表:用户表和账户表
            * 让用户表和账户表具备一对多的关系,需要使用外键在账户中添加
        2. 建立两个实体类,用户实体类和账户实体类
            1. 让用户和账户的实体类能体现出多对一(也是一对一)的关系
              * 做法: 在从表的实体类中放一个主表的实体类的引用,生成get,set方法
            2. 让用户和账户体现出一对多的关系
                * 做法: 在主表的实体类中包含从表实体的集合引用
        3. 建立两个配置文件
            * 用户的配置文件
            * 账户的配置文件
                * 账户的配置文件当建立一对一的关系映射时,封装user的内容的时候,需要提供javaType 的值 即user(如果没有配置别名,就要写全类名)
        4. 实现配置
            * 当我们查询用户时,可以同时得到用户下所包含的账户信息(一对多)
                * 配置文件中重要的resultMap(IUserDao中的):用到的是 collection 标签,ofType属性
                                <!--定义USer的resultMap-->
                                    <resultMap id="userAccountMap" type="user">
                                        <id property="id" column="id"></id>
                                        <result property="username" column="username"></result>
                                        <result property="address" column="address"></result>
                                        <result property="sex" column="sex"></result>
                                        <result property="birthday" column="birthday"></result>
                                        <!--配置user对象中的accounts集合的映射-->
                                        <collection property="accounts" ofType="account">
                                            <id column="aid" property="id" ></id>
                                            <result  column="uid" property="uid"></result>
                                            <result column="money" property="money" ></result>
                                        </collection>
                                    </resultMap>
            * 当我们查询账户时,可以同时得到账户的所属用户信息(多对一/一对一)
                 * 配置文件中重要的resultMap(IAccountDao中的):用到的是asscoiation 标签,和javaType属性 以及column属性
                                    <!--定义封装account和user的resultMap-->
                                        <resultMap id="accountUserMap" type="account">
                                            <id property="id" column="uid"></id>
                                            <result property="uid" column="uid"></result>
                                            <result property="money" column="money"></result>
                                            <!--一对一的关系映射,配置好的user的内容-->
                                            <association property="user" column="uid" javaType="user">
                                                <id property="id" column="id"></id>
                                                <result  property="username" column="username"></result>
                                                <result property="address" column="address"></result>
                                                <result property="sex" column="sex"></result>
                                                <result property="birthday" column="birthday"></result>
                                            </association>
                                        </resultMap>
    4. MyBatista中的多表查询示例: 用户和角色 (多对多)
        * 一个用户可以有多个角色
        * 一个角色可以赋予多个用户

Mybatis 中的延迟加载策略

1. 定义: 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载. 
2. 好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
3. 坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
4. 一般一对一的时候是立即加载,多对一的时候是延迟加载

Mybatis缓存

1. 像大多数的持久化框架一样,Mybatis也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。 Mybatis中缓存分为一级缓存,二级缓存。
2. 一级缓存:一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit(),close()等方法时,就会清空一级缓
    1. 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
3. 二级缓存 :二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

Mybatis使用注解开发

1. SqlMapConfig.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="jdbcConfig.properties"></properties>
            <!--配置实体类别名-->
            <typeAliases>
                <package name="com.itheima.domin"></package>
            </typeAliases>
            <!--配置环境-->
            <environments default="mysql">
                <environment id="mysql ">
                    <transactionManager type="JDBC"></transactionManager>
                    <dataSource type="POOLED">
                        <property name="dirver" value="${jdbc.driver}"/>
                        <property name="url" value="${jdbc.url}"/>
                        <property name="password" value="${jdbc.password}"/>
                        <property name="username" value="${jdbc.username}"/>
                        
                    </dataSource>
                </environment>
            </environments>
            <!--指定带有注解的dao接口所在的位置-->
            <mappers>
                <package name="com.itheima.dao"/>
            </mappers>
        </configuration>
2. 在MyBatista中CRUD(Create ,Retrieve, Update,Delete)一共有四个注解
    1. @Select
        * 查询所有用户:@Select(value="select * from user") ,其中value可以省略不写
    2. @Insert
    3. @Update
    4. @Delete
3.复杂关系映射的注解说明
        1. @Results注解
        代替的是标签<resultMap>
        该注解中可以使用单个@Result注解,也可以使用@Result集合
        @Results({@Result(),@Result()})或@Results(@Result())
        @Resutl注解
        代替了 <id>标签和<result>标签
        @Result 中 属性介绍:
                id 是否是主键字段
                column 数据库的列名
                property需要装配的属性名
                one 需要使用的@One注解(@Result(one=@One)()))
                many 需要使用的@Many注解(@Result(many=@many)()))
        @One注解(一对一)
                代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
        @One注解属性介绍:
                select 指定用来多表查询的sqlmapper
                fetchType会覆盖全局的配置参数lazyLoadingEnabled。。
                使用格式: @Result(column=" ",property="",one=@One(select=""))
        @Many注解(多对一) 代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
                注意:聚集元素用来处理“一对多”的关系。需要指定映射的Java实体类的属性,属性的javaType(一般为ArrayList)但是注解中li可以不定义;
                使用格式: @Result(property="",column="",many=@Many(select=""))
        2. 示例(多对一,也就是一对一):
            /**
             * 查询所有账户,并且获取每个账户所属的用户信息
             * @return
             */
            @Select("select * from account")
            @Results(id="accountMap",value = {
                    @Result(id=true,column = "id",property = "id"),
                    @Result(column = "uid",property = "uid"),
                    @Result(column = "money",property = "money"),
                    @Result(property = "user",
                column = "uid",
                one=@One(select="com.itheima.dao.IUserDao.findById",
                        fetchType= FetchType.EAGER))
            })
            List<Account> findAll();
        
            /**
             * 根据用户id查询账户信息
             * @param userId
             * @return
             */
            @Select("select * from account where uid = #{userId}")
            List<Account> findAccountByUid(Integer userId);
        3. 示例(一对多,一般采用延迟加载)
            
                /**
                 * 查询所有用户
                 * @return
                 */
                @Select("select * from user")
                @Results(id="userMap",value={
                        @Result(id=true,column = "id",property = "userId"),
                        @Result(column = "username",property = "userName"),
                        @Result(column = "address",property = "userAddress"),
                        @Result(column = "sex",property = "userSex"),
                        @Result(column = "birthday",property = "userBirthday"),
                        @Result(property = "accounts",column = "id",
                                many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
                                            fetchType = FetchType.LAZY))
                })
                List<User> findAll();
    4. MyBatista基于注解的二级缓存(每次查询都需要最新数据的sql,要禁用二级缓存)
        1. 在SqlMapConfig.xml 中开启二级缓存支持(默认就是开启)
             <!-- 配置二级缓存 --> 
             <settings> 
                <!-- 开启二级缓存的支持 --> 
                <setting name="cacheEnabled" value="true"/> 
             </settings>
        2.  在持久层接口中使用注解配置二级缓存
            @CacheNamespace(blocking=true)//mybatis基于注解方式实现配置二级缓存 
            public interface IUserDao {}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容