mybatis 养吾剑总结

mybatis 养吾剑总结

基本配置

创建mybatis的主配置文件,指定数据库环境和事务类型

<?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>
    <settings>
		<setting name="logImpl" value="LOG4J"/>
		<setting name="jdbcTypeForNull" value="NULL"/>
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>
    <typeAliases>
		<package name="com.jp.haiyou.attendance.web.vo"/>
	</typeAliases>
    <!--environments是所有环境标签,子标签是单个的数据库环境。可以指定一个默认采用的数据库-->
    <environments default="mysql">
        <!--这里配置的是单个的数据库环境,这里是msql-->
        <environment id="mysql">
            <!--配置事务类型,这里采用jdbc-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置采用的连接池,这里使用内置的pooled-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="JIANGkui1"/>
            </dataSource>
        </environment>
    </environments>
    <!--指定配置文件的位置,mappers是指一个dao接口所对应的具体实现方式,其存放位置必须在resources的同名包下-->
    <mappers>
        <mapper resource="dao/IAccountDao.xml"/>
    </mappers>
</configuration>

如果不想将接口和mapper文件分别放到src/main/java和src/main/resources中,而是全部放到src/main/java,那么在构建的时候需要指定maven打包需要包括xml文件,具体配置如下:

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
       </resource>
    </resources>
</build>

创建和dao接口相匹配的映射配置文件

<mapper namespace="dao.IAccountDao">
<!--这里的dao里的id是方法名,如果方法有返回值,需要封装的话,需要通过resultType指定返回值类型-->
    <select id="findAll" resultType="domain.Account">
            select * from account
    </select>
</mapper>

sql语句简单的话,也可以使用注解的方式来配置sql语句

    @Select("select * from account")
    Account findAccountByname(String name);

不使用spring整合的话,需要自己配置SqlSessionFactory :

//      通过mybatis提供的resources工具类得到配置文件的流,然后使用工厂构建器构建使用该配置文件构建出的工厂
        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//      工厂生产session对象,这里我们主要使用的对象,该对象可以生产代理dao,并且一个session是一个事务
        SqlSession sqlSession = factory.openSession();
//        使用getmapper方法获得代理dao
        IAccountDao accountDao = sqlSession.getMapper(IAccountDao.class);
        List<Account> all = accountDao.findAll();
        for (Account account : all) {
            System.out.println(account);
        }
//        释放资源:由于流并不是給包装类使用的,这里注意要关闭流。
//        sqlSession.commit();
        sqlSession.close();
        in.close();

基本增删改查
<select id="findAll" resultType="domain.Account">
            select * from account
    </select>
    <!--占位符使用el表达式方式#{name},el表达式的作用域方法传入的参数parameterType,属性名是get方法.注意ddl都需要commit-->
    <!--selectKey三个属性分别表示属性名称,返回值类型,操作顺序,就是把select的结果注入到传入对象的id属性中去-->
    <!--非自增随机赋予uuid型逐渐也可以获取,order="befor" 返回值string 语句写select replace(uuid(), '-', '')即可-->
    <insert id="saveAccount" parameterType="domain.Account">
        <selectKey  keyProperty="id" resultType="int" order="AFTER">
            select last_insert_id()
        </selectKey>
        insert into account(name,money) values(#{name},#{money})
    </insert>

    <update id="updateAccount" parameterType="domain.Account">
        update account set name=#{name},money=#{money} where id=#{id}
    </update>

    <!--参数只有一个的情况下,占位符叫id或uid,可以随便取,它将按照类型获取值,类似autowire-->
    <delete id="deleteAccount" parameterType="int">
        delete from account where id=#{id}
    </delete>

    <select id="findAccountById" parameterType="int" resultType="domain.Account">
        select * from account where id=#{id}
    </select>

    <!--模糊查询时,可以写${value}的形式,这样可以拼接其他字符串,如%${value}%,这种形式中value的值是固定的,只能写value-->
    <select id="findAccountByName" parameterType="string" resultType="domain.Account">
        select * from account where name like #{name}
    </select>

    <select id="findTotal" resultType="int">
        select count(id) from account
    </select>

传入参数和返回值封装

【parameterType和resultType】
1、mybatis使用ognl(对象图导航语言)表达式解析对象的值,#/$括号中的域对象即为pojo对象。后者拼写时不会带‘’符号,所以要小写sql注入攻击。
2、显然,如果要使用跨关系查询时,只需要把多个对象组成一个查询vo对象或者map,然后在sql中调用即可。需要注意没有传值时的处理方式。
3、parameterType只是用来指定ognl表达式的域对象的,不写它时,可以用指定对象取值的方法来获取参数,如#{user.id}。多参数时,可以位置索引如#{0}来指定参数使用。
4、方法中直接使用注解定义参数别名,如@Param(“id”),xml可以直接使用#{id}。

【返回值封装】
数据库列名如果和entity类set方法名一致,可以自动封装,如果不一样,可以采用如下方法。
1、查询语句起别名。
2、使用resultMap 标签描述列名和实体类的对应关系。然后在select标签中把resultType换成resultMap即可。注意,以后所有使用到resultMap的地方也是一样的,所有实体类与数据列名一致的地方都可以省略。

 <resultMap id="accountMpa" type="domain.Account">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="money" column="money"/>
    </resultMap>
动态查询,多表查询
    <!--if test语句内可以不写#{}取得属性,但需要严格注意大小写,如果test为真,if内语句就会拼接到上面的select语句执行。可以使用!= == and or 等运算符。where子标签可以用于拼接where语句,可以把他看成自动写了一个where 1=1-->
   <select id="findAccountByCondition"  parameterType="domain.Account" resultType="domain.Account">
        select * from account
        <where>
            <if test="id != null">
                and id =#{id}
            </if>
            <if test="name != null">
                and name like #{name}
            </if>
            <if test="money != null">
                and money = #{money }
            </if>
        </where>
    </select>
	<!--for each标签,用来遍历集合拼接查询字符串-->
    <select id="findAccountByIdInIds" parameterType="queryVo" resultType="domain.Account">
        select * from account
        <where>
            <foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
                #{uid}
            </foreach>
        </where>
    </select>

多对一(一对一)

<mapper namespace="dao.IAccountDao">
<resultMap id="accountUserMap" type="domain.Account">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="money" column="money"/>
        <!--一对一的关系映射 property指定封装到内部哪一个对象,javatype指定类名-->
        <association property="user" javaType="domain.User" >
            <id property="id" column="user_id"/>
            <result property="userName" column="userName"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
        </association>
    </resultMap>
    <select id="findAll" resultMap="accountUserMap">
            select a.*,u.id user_id,u.address,u.birthday,u.sex,u.username from account a LEFT JOIN user u on 	a.userid=u.id
    </select>

一对多

<mapper namespace="dao.IUserDao">
    <resultMap id="userAccountMap" type="domain.User">
            <id property="id" column="id"/>
            <result property="userName" column="userName"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
        <collection property="accounts" ofType="domain.Account">
            <id property="id" column="aid"/>
            <result property="name" column="name"/>
            <result property="money" column="money"/>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="userAccountMap">
      select u.*,a.id aid,a.name,a.money from user u LEFT JOIN account a on u.id =a.userid
    </select>

多对多

<resultMap id="roleMap" type="domain.Role">
            <id property="roleId" column="roleId"/>
            <result property="roleName" column="roleName"/>
            <result property="roleDesc" column="roleDesc"/>
        <collection property="users" ofType="domain.User">
            <id property="id" column="id"/>
            <result property="userName" column="userName"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="roleMap">
        select r.*,u.* from `user` u
        RIGHT JOIN user_role ur on u.id=ur.uid
        RIGHT JOIN role r on r.roleId=ur.rid
    </select>
如果一个对象中需要封装多个集合,resultMap中需要定义多个集合,列名不能重复。sql语句需要多表联合,将所有对象都查出来。如下是User中封装了account和role对象的sql语句:
    <select id="findAll" resultMap="userAccountMap">
      select u.*,r.*,a.id aid ,a.name,a.money from `user` u
      LEFT JOIN user_role ur on u.id=ur.uid
      LEFT JOIN role r on r.roleId=ur.rid
      LEFT JOIN account a on a.userid=u.id
      ORDER  BY u.id;
    </select>

【延迟加载】

<!--使用到一对一的关联对象时,自动根据select的语句发关联查询,在查询时一起发送1+n条sql语句。如果不配置懒加载,并不会延迟-->
    <!--参数,column指外键列的列名,select是byid的语句,相当于select * from user where id=#{userid}。userid可以完全不在resultMap中体现。-->
    <resultMap id="account_user_lazy" type="account">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="money" column="money"/>
        <association property="user" javaType="user" column="userid" select="dao.IUserDao.findById"/>
    </resultMap>

主配置文件:

  <settings>
        <!--指定 MyBatis 所用日志的具体实现,未指定时将自动查找。-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
        <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载。-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

注意:懒加载时,调用tostring方法和getUser方法,都会触发sql语句发送。其他单独get属性时,并不会发送sql语句。

注意:懒加载时,调用tostring方法和getUser方法,都会触发sql语句发送。其他单独get属性时,并不会发送sql语句。

一对多查询时,写法也基本一样,查询user时,通过select属性指定一个accountdao的list findbyuserid(int uid)方法即可。传入的id值通过column参数指定本查询的id。相当于每次遍历一个User时,该配置会自动帮你调用一次findbyuserid方法。

缓存

1、sqlsession对象会默认缓存所有查询的结果集,这就是一级缓存。也就是说,在一个session中重复查询是没有意义的。但是,调用sqlsession.clearCache()可以清空缓存,清空后需要重新通过getMapper方法获取代理dao。
2、当调用sqlsession的修改,添加,删除,commit,close方法后,会自动清空一级缓存。
3、二级缓存是sqlsessionfactory级别的缓存,由一个工厂生产出的多个session共享同一个二级缓存。它存储的是数据,而非对象。它并不会发sql语句,但会将存储的数据新new一个对象交给调用方法,因此新建的对象内存地址是不同的。
4、二级缓存使用步骤:
1、在主配置文件中开启二级缓存。cacheEnabled=true
2、在映射文件的mapper标签中写。
3、在select标签中写userCache=“true”。

注解开发

1、单表情况下:删增改查的语句写法和xml一致。单参数情况下默认传入该参数作为作用域(基本类型直接按类型匹配),因此可以用#{属性名}的写法。多参数情况下,用@param注解修饰参数起别名,或者使用#{0}位置调用。

2、配置实体类映射的注解:

 @Results(id = "accountMap",
         value = {
         @Result(id = true,column = "id",property = "id"),
         @Result(property="name", column="name"),
         @Result(property="money", column="money"),
         @Result(property="userid", column="userid"),
 })

该注解标在方法上,方法返回值按该映射封装的同时,可以指定一个id名称,給其他方法进行引用。其他方法使用@ResultMap(“accountMap”)注解即可引用,而不用重新写对应关系。

3、多表懒加载

@Select("select * from account")
    @Results(
            value = {
                    @Result(id = true,column = "id",property = "id"),
                    @Result(property="name", column="name"),
                    @Result(property="money", column="money"),
                    @Result(property="userid", column="userid"),
                    @Result(property = "user",column = "userid",
                            one = @One(select = "dao.IUserDao.findById",fetchType = FetchType.LAZY))
            })

一对多情况下使用:

many = @Many(fetchType = FetchType.LAZY,select = "dao.IAccountDao.findAccountByUserId")

4、开启二级缓存,主配置文件开启后,在dao类名上使用@CacheNamespace(blocking=true)即可。
5、注解不支持逻辑判断和join查询,所以,复杂查询请尽量使用xml配置文件。

spring整合mybatis
<!--spring整合mybatis对象-->
    <bean id="factoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="htyy.domain"/>
        <!--所有settings的内容都可以写在这里-->
        <property name="configuration">
            <bean class="org.apache.ibatis.session.Configuration">
                <property name="lazyLoadingEnabled" value="true"/>
                <property name="aggressiveLazyLoading" value="false"/>
		<setting name="jdbcTypeForNull" value="NULL"/>
            </bean>
        </property>
        <!--引入原始的配置文件-->
        <!--<property name="configLocation" value="mybatis.xml"/>-->
        <!-- 当mybatis的xml文件和mapper接口不在相同包下时,需要用mapperLocations属性指定xml文件的路径。
        *是个通配符,代表所有的文件,**代表所有目录下 -->
        <!--<property name="mapperLocations" value="classpath:htyy/dao/**/*.xml"/>-->
    </bean>
    <!--4 自动扫描对象关系映射 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
        <!-- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> -->
        <!-- basePackage 属性是让你为映射器接口文件设置基本的包路径。 你可以使用分号或逗号 作为分隔符设置多于一个的包路径 -->
        <property name="basePackage" value="htyy.dao"/>
    </bean>
maven依赖
<dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>${mybatis.version}</version>
      </dependency>
      <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
          <version>1.3.0</version>
      </dependency>
      <dependency>
          <groupId>commons-fileupload</groupId>
          <artifactId>commons-fileupload</artifactId>
          <version>1.3.1</version>
      </dependency>
  </dependencies>

番外篇

【分页插件pagehelper】

mybatis没有分页功能,我们可以使用该插件进行增强

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.2</version>
        </dependency>

两种注册方式:

1、使用mybatis配置文件

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <property name="helperDialect" value="mysql"/>
            <property name="reasonable" value="true"></property>
        </plugin>
    </plugins>

2、使用spring整合

<property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            <prop key="helperDialect">mysql</prop>
                            <prop key="reasonable">true</prop>
                        </props>
                    </property>
                </bean>
            </array>
</property>

分页插件参数介绍

  • helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
    oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
    特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
    你也可以实现 AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。

  • offsetAsPageNum:默认值为 false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。

  • rowBoundsWithCount:默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。

  • pageSizeZero:默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。

  • reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。

  • params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。

  • supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest。

  • autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver),用法和注意事项参考下面的场景五。

  • closeConn:默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。

使用时,只需要在dao调用前执行startPage方法即可:

pageHelper.startPage(pageNum:1,pageSize:5)
List<User> users=UserDao.findAll();
//此时得到的users对象已经是分页后的,将它打包到pageinfo中即可。
PageInfo pageInfo=new PageInfo(users);

该pageInfo的一些属性如下:
1、size 当前页数量
2、total 总记录数
3、pages 总页数
4、list 结果集
5、prepage 前一页
6、nextpage
注意,pageinfo.list并不是list类型,而是一个page类型的lsit,因此print它并不会打印list信息。但遍历它可以获取存储的子条目

mybatis逆向工程插件

在不使用mybatis-plus的情况下,该插件可以很方便根据数据库表逆向生成entity和dao接口。

<plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.13</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <configurationFile>src/main/resources/generatorConfig.xml </configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
</plugin>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="mysqlgenerator" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
            <property name="enableSubPackages" value="false"/>
        </commentGenerator>

        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/test"
                        userId="root"
                        password="JIANGkui1" >
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>

        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
        <!-- targetProject:生成PO类的位置 -->
        <javaModelGenerator targetPackage="htyy.vo" targetProject="src/main/java" >
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- 对于mybatis来说,即生成Mapper接口,注意,如果没有配置该元素,那么默认不会生成Mapper接口 targetPackage/targetProject:同javaModelGenerator
            type:选择怎么生成mapper接口(在MyBatis3/MyBatis3Simple下):
            1,ANNOTATEDMAPPER:会生成使用Mapper接口+Annotation的方式创建(SQL生成在annotation中),不会生成对应的XML;
            2,MIXEDMAPPER:使用混合配置,会生成Mapper接口,并适当添加合适的Annotation,但是XML会生成在XML中;
            3,XMLMAPPER:会生成Mapper接口,接口完全依赖XML;
            注意,如果context是MyBatis3Simple:只支持ANNOTATEDMAPPER和XMLMAPPER -->
        <sqlMapGenerator targetPackage="htyy.dao" targetProject="src/main/java" />
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="MIXEDMAPPER" targetPackage="htyy.dao" targetProject="src/main/java" />
        <!-- 指定数据库表 -->
        <table tableName="account"
               enableCountByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               enableUpdateByExample="false">
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>
    </context>
</generatorConfiguration>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值