《Spring快速入门》读书笔记 第6章 MyBatis快速入门

个人读书笔记,题外话都写在第1章https://blog.csdn.net/u013652550/article/details/119800308


        第6章主要带我们学习了MyBatis相关知识,对ORM框架有了初步认识。本章关于配置的项目内容过于繁琐,很难记忆,用时查询即可。

6.1 ORM框架介绍

        ORM(Object Relation Mapping,对象关系映射)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

MyBatis的使用

        引入对应依赖即可,书本给的version是3.4.6,实测无效,自动填充为2.0.6。

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        MyBatis包含一个名叫Resources的工具类,包含一些实用方法,可方便地加载资源。这里使用Reader加载。亦可使用InputStream、Configuration等。调用openSession()、selectList、selectOne等方法使用。(可传入Object参数,如示例中的2,类似于PreparedStatement中的setter方法)

        String resource = "mybatis-config.xml";
        Reader reader = Resources.getResourceAsReader(resource);
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        String statement = "UserMapper.getUserList";
        List<User> users = session.selectList(statement);
        User u = session.selectOne(statement, 2);

6.2 XML配置

mybatis-config.xml

        主配置文件,顶层元素<configuration>,需要注意配置元素顺序匹配(可空)。[properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins? environments?, databaseIdProvider?, mappers?]

         以下列举一下书上提到的元素:

properties属性

        可使用resource进行外部引用,并进行补充。后续配置中可用${...}引用。注意覆盖优先级:通过方法参数传递的属性具有最高优先级,resource/url属性中指定的配置文件次之,最低优先级的是properties属性中指定的属性。

        <properties resource="database.properties">
            <property name="..." value="..."/>
        </properties>

 settings

        配置项过多,建议直接跳过,使用默认配置。详见书P95~97。使用<settings>内嵌套<setting name="..." value="..."/>配置。有效值留白为布尔类型(true|false)。

settings各项的意图、默认值
设置参数描述有效值默认值
cacheEnabled全局缓存true
lazyLoadingEnabled全局延迟加载false
aggressiveLazyLoading非按需加载false
multipleResultSetsEnabled允许单一语句多返回集true
useColumnLabel使用列标签代替列名true
useGeneratedKeys允许JDBC支持自动生成主键false
autoMappingBehavior如何自动映射NONE, PARTIAL, FULLPARTIAL
autoMappingUnknownColumnBehavior未知列映射NONE, WARNING, FAILINGNONE
defaultExecutorType默认执行器SIMPLE, REUSE, BATCHSIMPLE
defaultStatementTimeout超时时间正整数null
defaultFetchSize结果集数量提示值正整数null
safeRowBoundsEnabled允许嵌套语句中分页false
safeResultHandlerEnabled允许嵌套语句中分页true
mapUnderscoreToCamelCase自动开启驼峰命名规则映射false
localCacheScope加速重复嵌套SESSION, STATEMENTSESSION
jdbcTypeForNull空值类型JdbcType常量OTHER
lazyLoadTriggerMethods设置触发延迟加载的方法名CSV(逗号分隔值)equals, clone, hashCode, toString
defaultScriptingLanguage动态SQL默认语言类型别名或完全限定类名org.apache.ibatis.scripting.
xmltags.XMLLanguageDriver
defaultEnumTypeHandler指定Enum使用的默认TypeHandler类型别名或完全限定类名org.apache.ibatis.type.
EnumTypeHandler
callSettersOnNulls结果集中值为nul时是否调用setter方法false
returnInstanceForEmptyRow返回空行而不是nullfalse
logPrefix日志前缀Stringnull
proxyFactory延迟加载对象代理CGLIB, JAVASSISTJAVASSIST
vfsImplVFS(虚拟文件系统)实现CSV,全限定类名null
useActualParamName使用方法签名中的名称作为语句参数名称true
configurationFactory指定提供Configuration实例的类类型别名或全类名null

typeAliases

        设置别名。或在指定包名下搜索,在没有注解@Alias的情况下,使用Bean的非限定类名来作为它的别名。

    <typeAliases>
        <typeAlias type="com..." alias="xxx"/> 
        <package name="com..."/>
    </typeAliases>

typeHandlers

        默认类型处理器:见书P99~100。注意enum使用EnumTypeHandler存储name值,使用EnumOrdinalTypeHandler存储序号值。学习enum类型的使用:

public enum UserState {
    DISABLED(0),
    AVAILABLE(1);
    private final int status;
    UserState(int status) {
        this.status = status;
    }
    public int getStatus() {
        return status;
    }
}

        示例代码中:注意更新数据库(update, insert)后要调用session.commit()。

        自定义处理器:实现BaseTypeHandler<T>接口中的4个方法即可。

public class CusEnumStatusHandler extends BaseTypeHandler<UserState> {
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, UserState userState, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i, userState.getStatus());
    }
    @Override
    public UserState getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return UserState.fromValue(resultSet.getInt(s));
    }
    @Override
    public UserState getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return UserState.fromValue(resultSet.getInt(i));
    }
    @Override
    public UserState getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return UserState.fromValue(callableStatement.getInt(i));
    }
}

配置环境environments

        在项目开发过程中往往有几套环境,如开发、测试和生产环境。配置environments元素时只需加上default指定默认环境,每个环境都用environment元素嵌套在其中配置。此外,之前加载SqlSessionFactory时其实省略了第二、三个参数,即environment和properties。

        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);

        配置environment元素时指定id。然后依次配置:

        事务管理器transactionManager:type可以为JDBC或MANAGED,区别在于后者让容器管理事务。如果需要,设置closeConnection为false阻止默认关闭连接。如果使用Spring就没有必要配置事务管理器,Spring模块会使用自带的管理器来覆盖前面的配置。

            <transactionManager type="JDBC">
                <property name="closeConnection" value="false"/>
            </transactionManager>

        数据源dataSource:type可以为UNPOOLED、POOLED、JNDI。详见书P106。
                UNPOOLED:在每次请求时打开和关闭连接。包含driver、url、username、password、defaultTransactionIsolationLevel(默认事务隔离级别) 5个属性。
                POOLED:利用“池”获得更快的速度。在UNPOOLED的基础上还有以下更多属性:poolMaximumActiveConnections(最大同时连接数)、poolMaximumIdleConnections(最大空闲连接数)、poolMaximumCheckoutTime(被检出最长时间,默认20000ms)、poolTimeToWait(最长等待时间,默认20000ms)、poolMaximumLocalBadConnectionTolerance(坏连接容忍度,默认3)、poolPingQuery(侦测查询)、poolPingEnabled(是否启用侦测查询)、poolPingConnectionsNotUsedFor(侦测查询频率,默认0)。
                JNDI:为了能在EJB等容器中使用,放置一个JNDI上下文的引用即可。属性有两个:initial_context、data_source。

映射器mappers

        一般在同级目录下新建mapper文件夹存储映射配置文件。

    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>

6.3 XML映射文件

        以下列举可配置属性列表,通过单词含义基本能见名知意。

1. 查询元素select

        idparameterTyperesultTyperesultMap、flushCache、useCache、timeout、fetchSize(设置批量返回行数)、statementType(STATEMENT、PREPARED、CALLABLE,默认为PREPARED)、resultSetType(FORWARD_ONLY、SCROLL_SENSITIVE、SCROLL_INSENSITIVE,默认null)、databaseId(配置databaseIdProvider后生效)、resultOrdered(嵌套结果集而不是引用,默认false)、resultSets(CSV,给多结果集分别命名)。

2. 更新元素insert、update、delete

        idparameterType、flushCache、timeout、statementType、useGeneratedKeys(默认false)、keyProperty(标记属性,设置返回主键值,默认null,可以为CSV)、keyColumn(通过生成键值设置列名,可以为CSV)、databaseId。

    <insert id="addUser" parameterType="user">
        <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into t_user (name, age, money, status) values (#{name}, #{age}, #{money}, #{status, typeHandler=org.apache.ibatis.type.EnumTypeHandler})
    </insert>

        selectKey元素属性:idparameterTyperesultTyperesultMap、flushCache、useCache。

3. 可重用语句块sql

        为sql语句块设置id后即可使用include包含。属性值可以用在include元素的refid属性里或include内部语句中。可以在语句中使用${...},使用include时用property设置。贴一下书本示例:

    <sql id="userColumns">
        ${alias}.id, ${alias}.name, ${alias}.age, ${alias}.money, ${alias}.status
    </sql>
    <sql id="sometable">
        ${prefix}user as ${alias}
    </sql>
    <sql id="someinclude">
        from
            <include refid="${include_target}"/>
    </sql>
    <select id="getUserList2" resultMap="userResult">
        select
            <include refid="userColumns">
                <property name="alias" value="t1"/>
            </include>
            <include refid="someinclude">
                <property name="prefix" value="t_"/>
                <property name="alias" value="t1"/>
                <property name="include_target" value="sometable"/>
            </include>
    </select>

4. 数据集映射resultMap

        constructor:包含idArg、arg。构造方法注入。
        id:结果ID。
        result:普通结果。常用column、property。属性注入。
        association:关联类型。常用property、javaType(类型名)。使用resultMap直接引用已有映射集。
        collection:关联类型集合。常用property、javaType(类型名)、ofType(集合类型)。使用resultMap直接引用已有映射集。
        discriminator:根据结果值决定使用哪个resultMap。类似于switch-case语法。

5. 缓存和自定义缓存

        MyBatis默认开启一级缓存:同一个SqlSession,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询。

        默认不开启二级缓存。二级缓存可以在SqlSessionFactory层面给各个SqlSession对象共享。在配置中settings元素设置cacheEnabled参数为true,在映射文件中添加一行<cache/>即可。

    <cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>

        eviction:缓存回收策略。LRU:最少使用原则;FIFO:先进先出原则;SOFT:软引用;WEAK:弱引用。
        flushInterval:刷新时间间隔,单位ms。
        size:引用额数目。
        readOnly:设置为false时相同SQL后面访问的可能是cache的clone版本。

       在Mapper的具体方法下可以使用useCache、flushCache等设置对二级缓存的访问意愿。自定义缓存:实现org.apache.ibatis.cache.Cache接口。

public interface Cache {
    String getId();
    void putObject(Object key, Object value);
    Object getObject(Object key);
    Object removeObject(Object key);
    void clear();
    int getSize();
    default ReadWriteLock getReadWriteLock() {
        return null;
    }
}

        只有当调用了commit()方法,MyBatis才会往缓存中写入数据。

6.4 动态SQL

1. if语句

        示例中使用了两种传参数的方式:一种是string,另一种是map。用map可以传多个参数。bind的使用中可以在sql中增加%%。参数中可以不带。

    <select id="..." parameterType="string" resultMap="...">
        select * from t_user where 1=1
        <if test="_parameter!=null and _parameter!=''">
            and name like #{_parameter}
        </if>
    </select>
    <select id="..." parameterType="map" resultMap="...">
        <bind name="pattern value="'%' + _parameter.name + '%'" />
        select * from t_user where 1=1
        <if test="_parameter.name!=null and _parameter.name!=''">
            and name like #{pattern}
        </if>
    </select>

        以上演示了bind的使用。调用示例:

        List<User> users = session.selectList(statement, "%J%");

2. choose(when, otherwise)语句

        类似于switch-case-default语句的使用。配置示例:

        <choose>
            <when test="type=='city'">
                AND city like #{pattern}
            </when>
            <when ...>...</when>
            <otherwise>...</otherwise>
        </choose>

3. trim语句

        prefix:在trim标签内为sql语句加上前缀。
        suffix:在trim标签内为sql语句加上后缀。
        suffixOverrides:指定去除多余的后缀内容。
        prefixOverrides:制定去除多余的前缀内容。

    <trim prefix="set" suffixOverrides=",">
        <if test="_parameter.cardNo!=null and _parameter.cardNo!=''">
            cardNo = #{cardNo},
        </if>
        <if test="_parameter.city!=null and _parameter.city!=''">
            city = #{city},
        </if>
    </trim>
    <trim prefix="WHERE" prefixOverrides="and|or">
        <if test="_parameter.id!=null and _parameter.id!=''">
            and id = #{id}
        </if>
        <if test="_parameter.address!=null and _parameter.address!=''">
            and address = #{address}
        </if>
    </trim>

4. foreach语句

        Item:每个元素迭代时的别名。
        Index:每次迭代到的位置。
        Open:以什么开始。
        Separator:分隔符。
        Close:以什么结束。

        <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">

        调用示例:需要传递一个map参数。(复习自动拆包与解包)

        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
        Map<String, Object> map = new HashMap<>();
        map.put("ids", ids);
        List<User> users = session.selectList(statement, map);

6.5 逆向工程

        引入依赖:mybatis-generator-core,引入插件:maven-compiler-plugin和mybatis-generator-maven-plugin。之前已贴过很多引入的XML配置代码,以后不再贴。加载maven变更。

        书上对于逆向工程的使用仅仅贴了一段代码。关于逆向工程的使用这里有详细介绍:MyBatis逆向工程代码的生成以及使用详解(持续更新)_Oxygenzzz的博客-CSDN博客_mybatis逆向工程这里稍微剖析一下。顶层标签:generatorrConfiguration,然后是一项context,需设置id和targetRuntime("MyBatis3")。context包含如下元素:

commentGenerator

        设置suppressDate和suppressAllComments属性,布尔型。示例中均为true。

jdbcConnection

        设置数据库驱动,数据库地址及表名,账号,密码。driverClass、connectionURL、userId、password。

javaTypeResolver

        配置自定义类型解析器。使用属性<property name="..." value="..."/>配置。

javaModelGenerator

        生成Model类的包名及存放位置。示例:targetPackage="com..."、targetProject="src/main/java"。属性有两项,enableSubPackages、trimStrings,示例中均为true。

sqlMapGenerator

        生成映射文件的包名及存放位置。元素同上一项,但属性中无trimStrings。

javaClientGenerator

        生成DAO类的包名及存放位置。元素同上一项,增加了type(="XMLMAPPER")。

table

        生成对应表及类名。tableName、domainObjectName(设置实体名)、enableCountByExample、enableUpdateByExample、enableDeleteByExample、enableSelectByExample、selectByExampleQueryId。后五项示例中均为false。

6.6 分页插件pagehelper

        在pom.xml中引入pagehelper依赖。在mybatis-config.xml中配置拦截器。属性项dialet设置方言,rowBoundsWithCount默认为false,设置为true时使用RowBounds分页会进行count查询。

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialet" value="mysql"/>
            <property name="rowBoundsWithCount" value="true"/>
        </plugin>
    </plugins>

        调用示例代码如下:

        PageHelper.startPage(1, 5, true);
        PageInfo<Users> pageInfo = new PageInfo<User>(users);
        int 数据总数 = pageInfo.getTotal();
        int 数据总页数 = pageInfo.getPages();
        int 最后一页 = pageInfo.getLastPage();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值