zoukankan      html  css  js  c++  java
  • Mybatis入门

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

    入门

    1、引入jar

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>x.x.x</version>
    </dependency>

    2、配置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="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
      </mappers>
    </configuration>

    3、编写BlogMapper.xml

    <?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="org.mybatis.example.BlogMapper">
      <select id="selectBlog" resultType="Blog">
        select * from Blog where id = #{id}
      </select>
    </mapper>

    4、构建SqlSessionFactory、SQLSession查询

    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    // 首先它不是基于字符串常量的,就会更安全;其次,如果你的 IDE 有代码补全功能,那么你可以在有了已映射 SQL 语句的基础之上利用这个功能。
    SqlSession session = sqlSessionFactory.openSession(); try { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101); } finally { session.close(); }

    或者另外一种更古老的方式

    SqlSession session = sqlSessionFactory.openSession();
    try {
      Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
    } finally {
      session.close();
    }

    ps:命名空间,建议使用完全限定名如 org.mybatis.example.BlogMapper.selectBlog

    4、使用注解

    public interface BlogMapper {
      @Select("SELECT * FROM blog WHERE id = #{id}")
      Blog selectBlog(int id);
    }

    注解使代码显得更加简洁,但对于稍微复杂的语句就会力不从心,显得更加混乱。

    作用域和生命周期

    依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器(mapper)并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。但是其他对象的错误使用会导致严重的并发问题。

    SessionFactoryBuilder:这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域

    SqlSessionFactory:一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建,最佳作用域是应用作用域

    SqlSession:不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。而且返回一个响应,就关闭它。

    SqlSession session = sqlSessionFactory.openSession();
    try {
      // do work
    } finally {
      session.close();
    }

    Mapper:任何映射器实例的最大作用域是和请求它们的 SqlSession 相同的,在方法作用域

    编写Mapper.xml

    1、基本编写

    <select id="selectPerson" parameterType="int" resultType="hashmap">
      SELECT * FROM PERSON WHERE ID = #{id}
    </select>
    <insert id="insertAuthor"> insert into Author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio}) </insert> <update id="updateAuthor"> update Author set username = #{username}, password = #{password}, email = #{email}, bio = #{bio} where id = #{id} </update> <delete id="deleteAuthor"> delete from Author where id = #{id} </delete>

    #{id}是使得语句使用PrepareStatement执行,而${id}是将参数硬编人语句去执行,尽量使用#,能防止SQL注入。

    2、关于主键

    // 数据库支持自动生成主键
    <insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id"> insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio}) </insert>
    // 自定义主键
    <insert id="insertAuthor"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1 </selectKey> insert into Author (id, username, password, email,bio, favourite_section) values (#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR}) </insert>

    3、多行插入

    <insert id="insertAuthor" useGeneratedKeys="true"
        keyProperty="id">
      insert into Author (username, password, email, bio) values
      <foreach item="item" collection="list" separator=",">
        (#{item.username}, #{item.password}, #{item.email}, #{item.bio})
      </foreach>
    </insert>

    4、SQL片段

    <sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>

    使用include标签包含:

    <select id="selectUsers" resultType="map">
      select
        <include refid="userColumns"><property name="alias" value="t1"/></include>,
        <include refid="userColumns"><property name="alias" value="t2"/></include>
      from some_table t1
        cross join some_table t2
    </select>
    <sql id="sometable">
      ${prefix}Table
    </sql>
    
    <sql id="someinclude">
      from
        <include refid="${include_target}"/>
    </sql>
    
    <select id="select" resultType="map">
      select
        field1, field2, field3
      <include refid="someinclude">
        <property name="prefix" value="Some"/>
        <property name="include_target" value="sometable"/>
      </include>
    </select>

    5、Parameters

    // 简单对象
    <select id="selectUsers" resultType="User"> select id, username, password from users where id = #{id} </select>
    // 复杂对象
    <insert id="insertUser" parameterType="User"> insert into users (id, username, password) values (#{id}, #{username}, #{password}) </insert>

    指定一个特殊的数据类型:

    #{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
    #{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
    #{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}
    #{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

    6、Java Bean:

    // 最简单的map
    <select id="selectUsers" resultType="map"> select id, username, hashedPassword from some_table where id = #{id} </select>
    package com.someapp.model;
    public class User {
      private int id;
      private String username;
      private String hashedPassword;
      
      public int getId() {
        return id;
      }
      public void setId(int id) {
        this.id = id;
      }
      public String getUsername() {
        return username;
      }
      public void setUsername(String username) {
        this.username = username;
      }
      public String getHashedPassword() {
        return hashedPassword;
      }
      public void setHashedPassword(String hashedPassword) {
        this.hashedPassword = hashedPassword;
      }
    }
    <!-- In mybatis-config.xml file -->
    <typeAlias type="com.someapp.model.User" alias="User"/>
    
    <!-- In SQL Mapping XML file -->
    <select id="selectUsers" resultType="User">
      select id, username, hashedPassword
      from some_table
      where id = #{id}
    </select>

     7、Result Map

    <resultMap id="userResultMap" type="User">
      <id property="id" column="user_id" />
      <result property="username" column="user_name"/>
      <result property="password" column="hashed_password"/>
    </resultMap>
    
    <select id="selectUsers" resultMap="userResultMap">
      select user_id, user_name, hashed_password
      from some_table
      where id = #{id}
    </select>

    8、复杂映射Result Map

    <select id="selectBlogDetails" resultMap="detailedBlogResultMap">
      select
           B.id as blog_id,
           B.title as blog_title,
           B.author_id as blog_author_id,
           A.id as author_id,
           A.username as author_username,
           A.password as author_password,
           A.email as author_email,
           A.bio as author_bio,
           A.favourite_section as author_favourite_section,
           P.id as post_id,
           P.blog_id as post_blog_id,
           P.author_id as post_author_id,
           P.created_on as post_created_on,
           P.section as post_section,
           P.subject as post_subject,
           P.draft as draft,
           P.body as post_body,
           C.id as comment_id,
           C.post_id as comment_post_id,
           C.name as comment_name,
           C.comment as comment_text,
           T.id as tag_id,
           T.name as tag_name
      from Blog B
           left outer join Author A on B.author_id = A.id
           left outer join Post P on B.id = P.blog_id
           left outer join Comment C on P.id = C.post_id
           left outer join Post_Tag PT on PT.post_id = P.id
           left outer join Tag T on PT.tag_id = T.id
      where B.id = #{id}
    </select>
    <!-- 超复杂的 Result Map -->
    <resultMap id="detailedBlogResultMap" type="Blog">
      <constructor>
        <idArg column="blog_id" javaType="int"/>
      </constructor>
      <result property="title" column="blog_title"/>
      <association property="author" javaType="Author">
        <id property="id" column="author_id"/>
        <result property="username" column="author_username"/>
        <result property="password" column="author_password"/>
        <result property="email" column="author_email"/>
        <result property="bio" column="author_bio"/>
        <result property="favouriteSection" column="author_favourite_section"/>
      </association>
      <collection property="posts" ofType="Post">
        <id property="id" column="post_id"/>
        <result property="subject" column="post_subject"/>
        <association property="author" javaType="Author"/>
        <collection property="comments" ofType="Comment">
          <id property="id" column="comment_id"/>
        </collection>
        <collection property="tags" ofType="Tag" >
          <id property="id" column="tag_id"/>
        </collection>
        <discriminator javaType="int" column="draft">
          <case value="1" resultType="DraftPost"/>
        </discriminator>
      </collection>
    </resultMap>
    • constructor - 用于在实例化类时,注入结果到构造方法中id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
      • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
      • arg - 将被注入到构造方法的一个普通结果
    • result – 注入到字段或 JavaBean 属性的普通结果
    • association – 一个复杂类型的关联;许多结果将包装成这种类型
      • 嵌套结果映射 – 关联可以指定为一个 resultMap 元素,或者引用一个
    • collection – 一个复杂类型的集合
      • 嵌套结果映射 – 集合可以指定为一个 resultMap 元素,或者引用一个
    • discriminator – 使用结果值来决定使用哪个 resultMap
      • case – 基于某些值的结果映射
        • 嵌套结果映射 – 一个 case 也是一个映射它本身的结果,因此可以包含很多相 同的元素,或者它可以参照一个外部的 resultMap

    9、自动映射

    通常数据库列使用大写单词命名,单词间用下划线分隔;而java属性一般遵循驼峰命名法。 为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase设置为true。

    10、缓存

    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    • LRU – 最近最少使用的:移除最长时间不被使用的对象。
    • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

    缓存配置和缓存实例是绑定在 SQL 映射文件的命名空间是很重要的。因此,所有 在相同命名空间的语句正如绑定的缓存一样。 语句可以修改和缓存交互的方式, 或在语句的 语句的基础上使用两种简单的属性来完全排除它们。默认情况下,语句可以这样来配置:

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

    因为那些是默认的,你明显不能明确地以这种方式来配置一条语句。相反,如果你想改 变默认的行为,只能设置 flushCache 和 useCache 属性。比如,在一些情况下你也许想排除 从缓存中查询特定语句结果,或者你也许想要一个查询语句来刷新缓存。相似地,你也许有 一些更新语句依靠执行而不需要刷新缓存。

    动态SQL

    IF

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’ 
      <if test="title != null">
        AND title like #{title}
      </if>
      <if test="author != null and author.name != null">
        AND author_name like #{author.name}
      </if>
    </select>

    CHOOSE WHEN OTHERWISE

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’
      <choose>
        <when test="title != null">
          AND title like #{title}
        </when>
        <when test="author != null and author.name != null">
          AND author_name like #{author.name}
        </when>
        <otherwise>
          AND featured = 1
        </otherwise>
      </choose>
    </select>

    TRIM WHERE SET

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG 
      <where> 
        <if test="state != null">
             state = #{state}
        </if> 
        <if test="title != null">
            AND title like #{title}
        </if>
        <if test="author != null and author.name != null">
            AND author_name like #{author.name}
        </if>
      </where>
    </select>
    <update id="updateAuthorIfNecessary">
      update Author
        <set>
          <if test="username != null">username=#{username},</if>
          <if test="password != null">password=#{password},</if>
          <if test="email != null">email=#{email},</if>
          <if test="bio != null">bio=#{bio}</if>
        </set>
      where id=#{id}
    </update>

    如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

    <trim prefix="WHERE" prefixOverrides="AND |OR ">
      ... 
    </trim>
    <trim prefix="SET" suffixOverrides=",">
      ...
    </trim>

    FOREACH

    对一个集合遍历,通常用于构建in:

    <select id="selectPostIn" resultType="domain.blog.Post">
      SELECT *
      FROM POST P
      WHERE ID in
      <foreach item="item" index="index" collection="list"
          open="(" separator="," close=")">
            #{item}
      </foreach>
    </select>

    BIND

    bind元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

    <select id="selectBlogsLike" resultType="Blog">
      <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
      SELECT * FROM BLOG
      WHERE title LIKE #{pattern}
    </select>

    多数据库支持

    一个配置了“_databaseId”变量的 databaseIdProvider 可用于动态代码中,这样就可以根据不同的数据库厂商构建特定的语句。比如:

    <insert id="insert">
      <selectKey keyProperty="id" resultType="int" order="BEFORE">
        <if test="_databaseId == 'oracle'">
          select seq_users.nextval from dual
        </if>
        <if test="_databaseId == 'db2'">
          select nextval for seq_users from sysibm.sysdummy1"
        </if>
      </selectKey>
      insert into users values (#{id}, #{name})
    </insert>

    注解

    @CacheNamespace <cache> 为给定的命名空间(比如类)配置缓存。属性有:implemetationevictionflushIntervalsizereadWriteblocking 和properties
    @Property N/A <property> 指定参数值或占位值(placeholder)(能被 mybatis-config.xml内的配置属性覆盖)。属性有:namevalue。(仅在MyBatis 3.4.2以上版本生效)
    @CacheNamespaceRef <cacheRef> 参照另外一个命名空间的缓存来使用。属性有:valuename。如果你使用了这个注解,你应设置 value 或者 name 属性的其中一个。value 属性用于指定 Java 类型而指定命名空间(命名空间名就是指定的 Java 类型的全限定名),name 属性(这个属性仅在MyBatis 3.4.2以上版本生效)直接指定了命名空间的名字。
    @ConstructorArgs 方法 <constructor> 收集一组结果传递给一个结果对象的构造方法。属性有:value,它是形式参数数组。
    @Arg N/A
    • <arg>
    • <idArg>
    单参数构造方法,是 ConstructorArgs 集合的一部分。属性有:idcolumnjavaTypejdbcTypetypeHandlerselect 和 resultMap。id 属性是布尔值,来标识用于比较的属性,和<idArg> XML 元素相似。
    @TypeDiscriminator 方法 <discriminator> 一组实例值被用来决定结果映射的表现。属性有:columnjavaTypejdbcTypetypeHandler 和 cases。cases 属性是实例数组。
    @Case N/A <case> 单独实例的值和它对应的映射。属性有:valuetyperesults。results 属性是结果数组,因此这个注解和实际的 ResultMap 很相似,由下面的 Results 注解指定。
    @Results 方法 <resultMap> 结果映射的列表,包含了一个特别结果列如何被映射到属性或字段的详情。属性有:valueid。value 属性是 Result 注解的数组。这个 id 的属性是结果映射的名称。
    @Result N/A
    • <result>
    • <id>
    在列和属性或字段之间的单独结果映射。属性有:idcolumnjavaTypejdbcTypetypeHandleronemany。id 属性是一个布尔值,来标识应该被用于比较(和在 XML 映射中的<id>相似)的属性。one 属性是单独的联系,和 <association> 相似,而 many 属性是对集合而言的,和<collection>相似。它们这样命名是为了避免名称冲突。
    @One N/A <association> 复杂类型的单独属性值映射。属性有:select,已映射语句(也就是映射器方法)的全限定名,它可以加载合适类型的实例。fetchType会覆盖全局的配置参数 lazyLoadingEnabled注意联合映射在注解 API中是不支持的。这是因为 Java 注解的限制,不允许循环引用。
    @Many N/A <collection> 映射到复杂类型的集合属性。属性有:select,已映射语句(也就是映射器方法)的全限定名,它可以加载合适类型的实例的集合,fetchType 会覆盖全局的配置参数 lazyLoadingEnabled注意 联合映射在注解 API中是不支持的。这是因为 Java 注解的限制,不允许循环引用
    @MapKey 方法   这是一个用在返回值为 Map 的方法上的注解。它能够将存放对象的 List 转化为 key 值为对象的某一属性的 Map。属性有: value,填入的是对象的属性名,作为 Map 的 key 值。
    @Options 方法 映射语句的属性 这个注解提供访问大范围的交换和配置选项的入口,它们通常在映射语句上作为属性出现。Options 注解提供了通俗易懂的方式来访问它们,而不是让每条语句注解变复杂。属性有:useCache=trueflushCache=FlushCachePolicy.DEFAULTresultSetType=FORWARD_ONLYstatementType=PREPAREDfetchSize=-1timeout=-1useGeneratedKeys=falsekeyProperty="id"keyColumn=""resultSets=""。值得一提的是, Java 注解无法指定 null 值。因此,一旦你使用了 Options 注解,你的语句就会被上述属性的默认值所影响。要注意避免默认值带来的预期以外的行为。

           注意: keyColumn 属性只在某些数据库中有效(如 Oracle、PostgreSQL等)。请在插入语句一节查看更多关于 keyColumn 和 keyProperty 两者的有效值详情。
    • @Insert
    • @Update
    • @Delete
    • @Select
    方法
    • <insert>
    • <update>
    • <delete>
    • <select>
    这四个注解分别代表将会被执行的 SQL 语句。它们用字符串数组(或单个字符串)作为参数。如果传递的是字符串数组,字符串之间先会被填充一个空格再连接成单个完整的字符串。这有效避免了以 Java 代码构建 SQL 语句时的“丢失空格”的问题。然而,你也可以提前手动连接好字符串。属性有:value,填入的值是用来组成单个 SQL 语句的字符串数组。
    • @InsertProvider
    • @UpdateProvider
    • @DeleteProvider
    • @SelectProvider
    方法
    • <insert>
    • <update>
    • <delete>
    • <select>
    允许构建动态 SQL。这些备选的 SQL 注解允许你指定类名和返回在运行时执行的 SQL 语句的方法。(自从MyBatis 3.4.6开始,你可以用 CharSequence 代替 String 来返回类型返回值了。)当执行映射语句的时候,MyBatis 会实例化类并执行方法,类和方法就是填入了注解的值。你可以把已经传递给映射方法了的对象作为参数,"Mapper interface type" 和 "Mapper method" 会经过 ProviderContext (仅在MyBatis 3.4.5及以上支持)作为参数值。(MyBatis 3.4及以上的版本,支持多参数传入)属性有: typemethodtype 属性需填入类。method 需填入该类定义了的方法名。注意 接下来的小节将会讨论类,能帮助你更轻松地构建动态 SQL。
    @Param 参数 N/A 如果你的映射方法的形参有多个,这个注解使用在映射方法的参数上就能为它们取自定义名字。若不给出自定义名字,多参数(不包括 RowBounds 参数)则先以 "param" 作前缀,再加上它们的参数位置作为参数别名。例如 #{param1}#{param2},这个是默认值。如果注解是 @Param("person"),那么参数就会被命名为 #{person}
    @SelectKey 方法 <selectKey> 这个注解的功能与 <selectKey> 标签完全一致,用在已经被 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 注解了的方法上。若在未被上述四个注解的方法上作 @SelectKey 注解则视为无效。如果你指定了 @SelectKey 注解,那么 MyBatis 就会忽略掉由 @Options 注解所设置的生成主键或设置(configuration)属性。属性有:statement 填入将会被执行的 SQL 字符串数组,keyProperty 填入将会被更新的参数对象的属性的值,before 填入 true 或 false 以指明 SQL 语句应被在插入语句的之前还是之后执行。resultType 填入 keyProperty 的 Java 类型和用 Statement、 PreparedStatement 和 CallableStatement 中的 STATEMENT、 PREPARED 或 CALLABLE 中任一值填入 statementType。默认值是 PREPARED
    @ResultMap 方法 N/A 这个注解给 @Select 或者 @SelectProvider 提供在 XML 映射中的 <resultMap> 的id。这使得注解的 select 可以复用那些定义在 XML 中的 ResultMap。如果同一 select 注解中还存在 @Results 或者 @ConstructorArgs,那么这两个注解将被此注解覆盖。
    @ResultType 方法 N/A 此注解在使用了结果处理器的情况下使用。在这种情况下,返回类型为 void,所以 Mybatis 必须有一种方式决定对象的类型,用于构造每行数据。如果有 XML 的结果映射,请使用 @ResultMap注解。如果结果类型在 XML 的 <select> 节点中指定了,就不需要其他的注解了。其他情况下则使用此注解。比如,如果 @Select 注解在一个将使用结果处理器的方法上,那么返回类型必须是 void 并且这个注解(或者@ResultMap)必选。这个注解仅在方法返回类型是 void 的情况下生效。
    @Flush 方法 N/A 如果使用了这个注解,定义在 Mapper 接口中的方法能够调用 SqlSession#flushStatements() 方法。(Mybatis 3.3及以上)

    使用@SelectKey 注解来在插入前读取数据库序列的值:

    @Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
    @SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
    int insertTable3(Name name);

    指定 @Result 的 id 属性来命名结果集:

    @Results(id = "userResult", value = {
      @Result(property = "id", column = "uid", id = true),
      @Result(property = "firstName", column = "first_name"),
      @Result(property = "lastName", column = "last_name")
    })
    @Select("select * from users where id = #{id}")
    User getUserById(Integer id);
    
    @Results(id = "companyResults")
    @ConstructorArgs({
      @Arg(property = "id", column = "cid", id = true),
      @Arg(property = "name", column = "name")
    })
    @Select("select * from company where id = #{id}")
    Company getCompanyById(Integer id);

    单一参数使用 @SqlProvider 注解:

    @SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
    List<User> getUsersByName(String name);
    
    class UserSqlBuilder {
      public static String buildGetUsersByName(final String name) {
        return new SQL(){{
          SELECT("*");
          FROM("users");
          if (name != null) {
            WHERE("name like #{value} || '%'");
          }
          ORDER_BY("id");
        }}.toString();
      }
    }
    @SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
    List<User> getUsersByName(String name);
    
    class UserSqlBuilder {
      public static String buildGetUsersByName(final String name) {
        return new SQL(){{
          SELECT("*");
          FROM("users");
          if (name != null) {
            WHERE("name like #{value} || '%'");
          }
          ORDER_BY("id");
        }}.toString();
      }
    }
    @SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
    List<User> getUsersByName(
        @Param("name") String name, @Param("orderByColumn") String orderByColumn);
    
    class UserSqlBuilder {
    
      // If not use @Param, you should be define same arguments with mapper method
      public static String buildGetUsersByName(
          final String name, final String orderByColumn) {
        return new SQL(){{
          SELECT("*");
          FROM("users");
          WHERE("name like #{name} || '%'");
          ORDER_BY(orderByColumn);
        }}.toString();
      }
    
      // If use @Param, you can define only arguments to be used
      public static String buildGetUsersByName(@Param("orderByColumn") final String orderByColumn) {
        return new SQL(){{
          SELECT("*");
          FROM("users");
          WHERE("name like #{name} || '%'");
          ORDER_BY(orderByColumn);
        }}.toString();
      }
    }

    SQL语句构建器

    private String selectPersonSql() {
      return new SQL() {{
        SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME");
        SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON");
        FROM("PERSON P");
        FROM("ACCOUNT A");
        INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID");
        INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID");
        WHERE("P.ID = A.ID");
        WHERE("P.FIRST_NAME like ?");
        OR();
        WHERE("P.LAST_NAME like ?");
        GROUP_BY("P.ID");
        HAVING("P.LAST_NAME like ?");
        OR();
        HAVING("P.FIRST_NAME like ?");
        ORDER_BY("P.ID");
        ORDER_BY("P.FULL_NAME");
      }}.toString();
    }
    // Anonymous inner class
    public String deletePersonSql() {
      return new SQL() {{
        DELETE_FROM("PERSON");
        WHERE("ID = #{id}");
      }}.toString();
    }
    
    // Builder / Fluent style
    public String insertPersonSql() {
      String sql = new SQL()
        .INSERT_INTO("PERSON")
        .VALUES("ID, FIRST_NAME", "#{id}, #{firstName}")
        .VALUES("LAST_NAME", "#{lastName}")
        .toString();
      return sql;
    }
    
    // With conditionals (note the final parameters, required for the anonymous inner class to access them)
    public String selectPersonLike(final String id, final String firstName, final String lastName) {
      return new SQL() {{
        SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
        FROM("PERSON P");
        if (id != null) {
          WHERE("P.ID like #{id}");
        }
        if (firstName != null) {
          WHERE("P.FIRST_NAME like #{firstName}");
        }
        if (lastName != null) {
          WHERE("P.LAST_NAME like #{lastName}");
        }
        ORDER_BY("P.LAST_NAME");
      }}.toString();
    }
    
    public String deletePersonSql() {
      return new SQL() {{
        DELETE_FROM("PERSON");
        WHERE("ID = #{id}");
      }}.toString();
    }
    
    public String insertPersonSql() {
      return new SQL() {{
        INSERT_INTO("PERSON");
        VALUES("ID, FIRST_NAME", "#{id}, #{firstName}");
        VALUES("LAST_NAME", "#{lastName}");
      }}.toString();
    }
    
    public String updatePersonSql() {
      return new SQL() {{
        UPDATE("PERSON");
        SET("FIRST_NAME = #{firstName}");
        WHERE("ID = #{id}");
      }}.toString();
    }
    public String selectPersonSql() {
      return new SQL()
        .SELECT("P.ID", "A.USERNAME", "A.PASSWORD", "P.FULL_NAME", "D.DEPARTMENT_NAME", "C.COMPANY_NAME")
        .FROM("PERSON P", "ACCOUNT A")
        .INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID", "COMPANY C on D.COMPANY_ID = C.ID")
        .WHERE("P.ID = A.ID", "P.FULL_NAME like #{name}")
        .ORDER_BY("P.ID", "P.FULL_NAME")
        .toString();
    }
    
    public String insertPersonSql() {
      return new SQL()
        .INSERT_INTO("PERSON")
        .INTO_COLUMNS("ID", "FULL_NAME")
        .INTO_VALUES("#{id}", "#{fullName}")
        .toString();
    }
    
    public String updatePersonSql() {
      return new SQL()
        .UPDATE("PERSON")
        .SET("FULL_NAME = #{fullName}", "DATE_OF_BIRTH = #{dateOfBirth}")
        .WHERE("ID = #{id}")
        .toString();
    }
    方法描述
    • SELECT(String)
    • SELECT(String...)
    开始或插入到 SELECT子句。 可以被多次调用,参数也会添加到 SELECT子句。 参数通常使用逗号分隔的列名和别名列表,但也可以是数据库驱动程序接受的任意类型。
    • SELECT_DISTINCT(String)
    • SELECT_DISTINCT(String...)
    开始或插入到 SELECT子句, 也可以插入 DISTINCT关键字到生成的查询语句中。 可以被多次调用,参数也会添加到 SELECT子句。 参数通常使用逗号分隔的列名和别名列表,但也可以是数据库驱动程序接受的任意类型。
    • FROM(String)
    • FROM(String...)
    开始或插入到 FROM子句。 可以被多次调用,参数也会添加到 FROM子句。 参数通常是表名或别名,也可以是数据库驱动程序接受的任意类型。
    • JOIN(String)
    • JOIN(String...)
    • INNER_JOIN(String)
    • INNER_JOIN(String...)
    • LEFT_OUTER_JOIN(String)
    • LEFT_OUTER_JOIN(String...)
    • RIGHT_OUTER_JOIN(String)
    • RIGHT_OUTER_JOIN(String...)
    基于调用的方法,添加新的合适类型的 JOIN子句。 参数可以包含由列命和join on条件组合成标准的join。
    • WHERE(String)
    • WHERE(String...)
    插入新的 WHERE子句条件, 由AND链接。可以多次被调用,每次都由AND来链接新条件。使用 OR() 来分隔OR
    OR() 使用OR来分隔当前的 WHERE子句条件。 可以被多次调用,但在一行中多次调用或生成不稳定的SQL
    AND() 使用AND来分隔当前的 WHERE子句条件。 可以被多次调用,但在一行中多次调用或生成不稳定的SQL。因为 WHERE 和 HAVING 二者都会自动链接 AND, 这是非常罕见的方法,只是为了完整性才被使用。
    • GROUP_BY(String)
    • GROUP_BY(String...)
    插入新的 GROUP BY子句元素,由逗号连接。 可以被多次调用,每次都由逗号连接新的条件。
    • HAVING(String)
    • HAVING(String...)
    插入新的 HAVING子句条件。 由AND连接。可以被多次调用,每次都由AND来连接新的条件。使用 OR() 来分隔OR.
    • ORDER_BY(String)
    • ORDER_BY(String...)
    插入新的 ORDER BY子句元素, 由逗号连接。可以多次被调用,每次由逗号连接新的条件。
    DELETE_FROM(String) 开始一个delete语句并指定需要从哪个表删除的表名。通常它后面都会跟着WHERE语句!
    INSERT_INTO(String) 开始一个insert语句并指定需要插入数据的表名。后面都会跟着一个或者多个VALUES() or INTO_COLUMNS() and INTO_VALUES()。
    • SET(String)
    • SET(String...)
    针对update语句,插入到"set"列表中
    UPDATE(String) 开始一个update语句并指定需要更新的表明。后面都会跟着一个或者多个SET(),通常也会有一个WHERE()。
    VALUES(String, String) 插入到insert语句中。第一个参数是要插入的列名,第二个参数则是该列的值。
    INTO_COLUMNS(String...) Appends columns phrase to an insert statement. This should be call INTO_VALUES() with together.
    INTO_VALUES(String...) Appends values phrase to an insert statement. This should be call INTO_COLUMNS() with together.

    Springboot使用注解整合MyBatis案例:

    分页插件使用:

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

    1、配置

    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=123456

    2、配置分页

    pagehelper:
        helperDialect: mysql
        reasonable: true
        supportMethodsArguments: true
        params: count=countSql

    3、编写实体类

    public class User {
        private int id;
        private String name;
        private int age;
    
        public int getId() {    return id;    }
    
        public void setId(int id) { this.id = id;    }
    
        public String getName() {   return name;    }
    
        public void setName(String name) {  this.name = name;    }
    
        public int getAge() {   return age;    }
    
        public void setAge(int age) {   this.age = age;    }
    }

    4、编写Dao层

    @Mapper //1
    public interface UserDao {
        @Results({ //2
                @Result(property = "id", column = "id"), //2
                @Result(property = "name", column = "name"),
                @Result(property = "age", column = "age")
        })
        @Select("SELECT * FROM user WHERE age = #{age}") //3
        List<User> get(int age);
    
        @Insert("INSERT INTO user(name, age) VALUES (#{name}, #{age})") //3
        void insert(User user);
    }

    5、编写Service层

    @Transactional
    @Service //声明成一个spring bean
    public class UserService {
    
        @Autowired //连接到UserDao Bean
        private UserDao userDao;
    
        public String show() {
            return "Hello World!";
        }
    
        public List<User> showDao(int age) {
            return userDao.get(age);
        }
    
        public String insert(String name, int age) { //插入一条记录
            User user = new User();
            user.setName(name);
            user.setAge(age);
            userDao.insert(user);
            return "Insert ( ""+name+"", age"+age+") OK!";
        }

       public List<User> findAllUser(int pageNum, int pageSize) {
        //将参数传给这个方法就可以实现物理分页了,非常简单。
        PageHelper.startPage(pageNum, pageSize);
        return userMapper.selectAllUser();
       }
    }

    6、编写Controller

    @RestController //声明为一个Restful的Controller
    public class UserController {
        @Autowired //自动连接到UserService Bean
        private UserService userService;
    
        @RequestMapping(value = "/show")
        public String show() {
            return userService.show();
        }
    
        @RequestMapping(value = "/showDao")
        public Object showDao(int age) {
            return userService.showDao(age);
        }
    
        @RequestMapping(value="/insert")
        public String insert(String name, int age) {
            return userService.insert(name, age);
        }
    }
  • 相关阅读:
    禁止页面被复制和禁止右键,一段样式一段JS就行了,无需复杂设定!
    你不知道的DIV+CSS的命名规则
    帝国cms提高网站网页打开速度的手段
    帝国cms网站管理系统之安全设置最优化分享
    渗透测试===使用BURPSUIT暴力破解某网站的手机验证码
    并发、并行、同步、异步、多线程的区别?
    python基础===一行 Python 代码实现并行(转)
    python目前安装的包备份
    jmeter,测登录,要不要过滤掉JS,CSS等请求?感觉过滤掉了压出来的数据就不真实?
    几个网站
  • 原文地址:https://www.cnblogs.com/ijavanese/p/9610163.html
Copyright © 2011-2022 走看看