人大金仓数据库KingbaseES 支持的开发框架(基于JDBC)的 介绍和使用之二 之Mybaits篇

1.KES与Mybaits

1.1 Mybaits简介

MyBatis 是一个开源的持久层框架,它提供了将 SQL 语句与 Java 对象之间的映射关系进行配置的功能。它的目标是简化数据库访问的开发过程,提供灵活性和高性能。

MyBatis 的核心思想是将 SQL 语句与 Java 对象进行映射,通过配置文件或注解的方式,将 SQL 语句与数据库操作进行绑定。开发人员可以通过编写简单的 SQL 语句,将数据的增删改查操作与 Java 对象的属性进行关联,从而实现数据的持久化操作。

MyBatis 提供了以下主要特点:

灵活的 SQL 映射:MyBatis 允许开发人员使用 XML 配置文件或注解的方式,将 SQL 语句与 Java 对象进行映射。这样可以灵活地编写和管理 SQL 语句,使得开发人员可以更好地控制和优化数据库访问。

参数映射:MyBatis 支持将 Java 对象的属性与 SQL 语句中的参数进行映射,开发人员可以直接在 SQL 语句中使用对象的属性,而不需要手动拼接 SQL 语句。

结果映射:MyBatis 支持将 SQL 查询结果与 Java 对象进行映射,开发人员可以将查询结果直接映射为 Java 对象,简化了数据的处理过程。

缓存支持:MyBatis 提供了一级缓存和二级缓存的支持,可以提高数据库访问的性能。

插件扩展:MyBatis 允许开发人员编写插件来扩展框架的功能,可以在 SQL 执行前后进行拦截和处理,实现自定义的功能扩展。

总的来说,MyBatis 是一个简单、灵活且功能强大的持久层框架,它通过将 SQL 语句与 Java 对象进行映射,提供了方便的数据库访问方式,同时也提供了缓存支持和插件扩展等功能,使得开发人员可以更高效地进行数据库操作。

1.2 Mybaits原理

Mybatis 是非常流行的ORM框架,主要着力点在于 POJO 与 SQL 之间的映射关系。然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定 POJO 。相对Hibernate"O/R"而言,Mybatis 是一种"Sql Mapping"的ORM实现。

配置文件:配置数据库连接参数。

映射文件:配置SQL语句和JAVA核心类SqlSession的映射。

1.3 Mybatis支持的驱动形态

框架名称

方言包

支持的驱动形态

Mybatis

KES、PG形态

1.4 Mybatis使用场景

Mybatis可以单独使用,直接操作jdbc。也可以由spring,spring-boot等框架整合使用。 Mybatis主要应用于需求多变的互联网项目,例如电商项目等。

1.5 Mybatis与KES配置使用说明

Mybatis的jar包可以从官方网站下载,Mybatis所使用的JDBC包kingbase8-8.6.0.jar位于$KINGBASE_HOME/Interface/jdbc目录下。使用时将Mybatis包和JDBC包导入到项目的Libraries中并定义相关配置项即可。

1.5.1 定义Mybatis配置文件

根据用户选择,更改配置文件。在config.xml中配置JDBC的驱动信息参数,数据库服务器信息参数和登陆用户信息参数。当然,这些参数也可以根据用户应用需求,单独生成property文件,针对不用的应用场景,导入不同的属性文件。这里以property为例说明下config.xml的配置使用。

在property 中增加如下声明:

jdbc.driverClassName=com.kingbase8.Driver

jdbc.url=jdbc:kingbase8://localhost:54321/TEST

jdbc.username=登录名

jdbc.password=登录密码

在config.xml 中增加如下声明:

ini 复制代码
<environments default="development">

<environment id="development">

<transactionManager type="JDBC"/>

<dataSource type="POOLED">

<property name="driver" value="${jdbc.driverClassName}"/>

<property name="url" value="${jdbc.url}"/>

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

</dataSource>

</environment>

</environments>

1.5.2 配置mapper.xml

主要是配置SQL映射关系,根据用户的需求,自定义映射关系。这里以一个简单的配置为例。

在mapper.xml 中增加如下声明:

sql 复制代码
<mapper namespace="com.test.interfaces.MybatisDao">

<update id="dropTable">

DROP TABLE IF EXISTS ${sql} CASCADE

</update>

<update id="createNewTableMap" parameterType="java.util.HashMap">

${sql}

</update>

<resultMap id="NumTableMap" type="NumEntity">

<result column="id" property="userId" />

<result column="age" property="userAge" />

<result column="name" property="userName" />

<result column="wage" property="userWage" />

<result column="cost" property="userCost" />

</resultMap>

<select id="selectNumTable" resultMap="NumTableMap">

select * from t_num

</select>

<select id="selectNumTableByID" parameterType="int"

resultMap="NumTableMap">

select * from t_num where id=#{value}

</select>

<select id="selectNumTableByAge" parameterType="int"

resultMap="NumTableMap">

select * from t_num where age=#{value}

</select>

<select id="selectNumTableByName" parameterType="string"

resultMap="NumTableMap">

select * from t_num where name=#{value}

</select>

<insert id="insertNumTable" parameterType="NumEntity"

keyProperty="userId">

insert into t_num(id,age,name,wage,cost)

values(#{userId},#{userAge},#{userName},#{userWage},#{userCost})

</insert>

<update id="updateNumTableById" parameterType="NumEntity" >

update t_num set age=#{userAge},name=#{userName},wage=#{userWage},

cost=#{userCost}where id=#{userId}

</update>

<delete id="deleteNumTableById" parameterType="int">

delete from t_num where id=#{value}

</delete>

<delete id="deleteNumTable">

delete from t_num

</delete>

</mapper>

1.6 Mybatis程序示例

1.6.1 接口和实例开发示例

  • 在Java中读取property和config属性,配置到sqlSessionFactory

    @BeforeClass

    public static void setUpClass() throws Exception {

    InputStream fis = null;

    InputStream inputStream = null;

    try {

    /* 创建一个 sqlSessionFactory */

    Properties prop = new Properties();

    fis = Resources.getResourceAsStream("propertty");

    prop.load(fis);

    inputStream = Resources.getResourceAsStream("MyConfig.xml");

    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,

    "development", prop);

    } catch(Exception e) {

    e.printStackTrace();

    }

    }

  • 在Java中配置mapper.xml对应的namespace,为Interface类型

    public interface MybatisDao {

    int createNewTableMap(Map<String, Object> param);

    int dropTable(Map<String, Object> param);

    /*

    • new number table

    */

    public List selectNumTable();

    public NumEntity selectNumTableByID(int id);

    public List selectNumTableByAge(int age);

    public List selectNumTableByName(String name);

    public void insertNumTable(NumEntity user);

    public void updateNumTableById(NumEntity user);

    public void deleteNumTableById(int id);

    public void deleteNumTable();

    }

  • 在Java中进行表的查询操作

    public void testNumTable() {

    SqlSession session = sqlSessionFactory.openSession();

    int i = 1;

    try {

    MybatisDao userOperation = session.getMapper(MybatisDao.class);

    List users = userOperation.selectNumTable();

    for (NumEntity user : users) {

    System.out.println(user);

    Assert.assertEquals(i, user.getId());

    Assert.assertEquals(AGE+i, user.getUserAge());

    Assert.assertEquals(name[i], user.getUserName());

    Assert.assertEquals("yes",WAGE+(double)(i*100)/(double)(3.0),

    user.getUserWage(),0.000001);

    Assert.assertEquals("yes",COST+(double)(i*100)/(double)(3.0),

    user.getUserCost(),0.01);

    i++;

    }

    } finally {

    session.close();

    }

    }

  • 在Java中进行表的插入操作

    public void testInsertNumTable() {

    int i = 1 ;

    SqlSession session = sqlSessionFactory.openSession();

    try {

    MybatisDao userOperation = session.getMapper(MybatisDao.class);

    NumEntity user = new NumEntity();

    name[1] = "张三";

    name[2] = "李四";

    name[3] = "王五";

    name[4] = "赵二";

    name[5] = "小北";

    name[6] = "小东";

    name[7] = "小西";

    name[8] = "小南";

    name[9] = "小明";

    for (i=1;i<10;i++) {

    user.setId(i);

    user.setUserAge(AGE+i);

    user.setUserName(name[i]);

    user.setUserWage(WAGE+(double)(i*100)/(double)(3.0));

    user.setUserCost(COST+(double)(i*100)/(double)(3.0));

    userOperation.insertNumTable(user);

    session.commit();

    System.out.println(user);

    }

    } finally {

    session.close();

    }

    }

  • 在Java中进行表的更新操作

    public void testUpdateNumTable() {

    int i = 1 ;

    SqlSession session = sqlSessionFactory.openSession();

    try {

    MybatisDao userOperation = session.getMapper(MybatisDao.class);

    NumEntity user = new NumEntity();

    /* 更新一行新的数据id=1 */

    user = userOperation.selectNumTableByID(1);

    user.setUserAge(AGE+i);

    user.setUserName(name[0]);

    user.setUserWage(WAGE+(double)(i*100)/(double)(3.0));

    user.setUserCost(COST+(double)(i*100)/(double)(3.0));

    userOperation.updateNumTableById(user);

    session.commit();

    } finally {

    session.close();

    }

    }

  • 在Java中进行表的删除操作

    public void testDeleteNumTable() {

    int i = 1 ;

    SqlSession session = sqlSessionFactory.openSession();

    try {

    MybatisDao userOperation = session.getMapper(MybatisDao.class);

    userOperation.deleteNumTable();

    session.commit();

    } finally {

    session.close();

    }

    }

1.6.2 存储过程的使用

  • 如果开发过程中需使用数据库的存储过程,可在mapper.xml中增加如下内容:

    <select id="getPerson" resultType="java.util.Map"

    statementType="CALLABLE">

    {

    call getPerson(

    #{a,mode=IN,jdbcType=INTEGER},

    #{b,mode=OUT,jdbcType=VARCHAR},

    #{param2,mode=OUT,javaType=ResultSet,jdbcType=OTHER,resultMap=cursorMap}

    )

    }

  • 创建表和数据:

    create or replace function getPerson(b out refcursor)

    as $$

    begin

    open b for select * from person;

    end;
    <math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> </math>

  • 调用存储过程:

    Map<String, Object> map = mapper.getPerson2(null, null, null);

    ResultSet o = (ResultSet) map.get("getperson2");

    o.next();

    System.out.println(o.getString(1));

    System.out.println(o.getString(2));

    System.out.println(o.getString(3));

1.7 注意事项

  • KingbaseES支持array数据类型,在MyBatis中需要增加ArrayTypeHandler来处理这一特殊类型;
  • KingbaseES支持json数据类型,在Mybatis中需要增加JsonTypeHandler来处理这一特殊类型;
  • KingbaseES支持hstore数据类型,在Mybatis中需要增加HstoreTypeHandler来处理这一特殊类型;
  • KingbaseES支持XML数据类型,在Mybatis的映射中,需要对xml数据类型做标注,如:

insert into t_xml(value) values ((#{content})::xml)

  • KingbaseES适配Mybatis的pagehelper插件时,由于无法通过连接自动获取数据库类型,需要将helperDialect设置成postgresql,配置如下:

1.8 常见问题

Mybatis设置SQL超时时间

mybatis如果不指定,默认超时时间是不做限制的,默认值为0.

mybatis sql配置超时时间有两种方法:

1、全局配置

在mybatis配置文件的settings节点中,增加如下配置

xml 复制代码
<settings>  

<setting name="defaultStatementTimeout" value="25"/>  </settings> 
 

以秒为单位的全局SQL超时时间设置,当超出了设置的超时时间时,会抛出SQLTimeoutException

2、Mapper XML配置

在mapper xml文件中对具体一个sql进行设置,方法为在select/update/insert节点中配置timeout属性,超时时间并只作用于这一个sql.

ini 复制代码
<insert  

  id="insert"  

  parameterType="com.test.abc.Person"  

  flushCache="true"  

  statementType="PREPARED"  

  keyProperty=""  

  keyColumn=""  

  useGeneratedKeys=""  

  timeout="10">
  • Mybatis非法long值问题

答:1:这个问题是由于V7的JDBC默认把TEXT类型对应为LONGVARCHAR,而Mybatis又把LONGVARCHAR类型默认按照CLOB对象处理,造成和Hibernate非法long值的情形类似,但是Mybatis没有提供方言机制,所以无法像Hibernate那样同过方言包控制,只能把V7的JDBC的TEXT类的值对应到Varchar来处理,就解决非法值问题。

2:如果用新的JDBC还出此问题,说明用户自己把string类型的jdbcType手动设置为LONGVARCHAR了。解决办法:就是把jdbcType去掉或者设置为VARCAHR即可。

  • Mybatis 报错:字段的类型为 TEXT, 但表达式的类型为 BYTEA你需要重写或转换表达式

答:1:这个问题需要查看出错SQL的mapper文件,需要知道mapper中参数是否指定了类型,从正常逻辑上来说不应该出现这样的转换,应该可通过调整参数类型解决。

2:这个也可以从JDBC入手,把所有Bind参数设置Oid.BYTEA的全都改为0,让服务器自己推断类型。

  • Mybatis 控制JDBC底层不走预编译

答:在mapper文件中可以使用statementType标记使用什么的对象操作SQL语句。 statementType:标记操作SQL的对象 ,如statementType="STATEMENT"

要实现动态传入表名、列名,需要做如下修改,sql里的所有变量取值都改成${xxxx},而不是#{xxx}

取值说明:

1、STATEMENT:直接操作sql,不进行预编译,获取数据:$---Statement

2、PREPARED:预处理,参数,进行预编译,获取数据:#-----PreparedStatement:默认

3、CALLABLE:执行存储过程------------CallableStatement

  • Mybatis 控制Bind参数

答:#{}:相当于JDBC中的PreparedStatement,走Bind报文。

${}:是输出变量的值,字串替换,不走Bind。

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

  • Mybatis 使用pagehelper插件

Mybatis使用该插件需要将helperDialect设置成postgresql,如不指定,会报错:com.github.pagehelper.PageException

无法自动获取数据库类型,请通过helperDialect

数指定!

1.直接使用Mybatis设置如下:

xml 复制代码
<plugins>

                   <!-- com.github.pagehelper为PageHelper类所在包名 -->

                   <plugin interceptor="com.github.pagehelper.PageInterceptor">

                            <property name="helperDialect" value="postgresql" />

                   </plugin>

        </plugins>

2.springboot整合mybatis使用如下:

在pom文件中引入Pagehelper分页插件:

xml 复制代码
<!-- 分页插件 -->

<dependency>

    <groupId>com.github.pagehelper</groupId>

    <artifactId>pagehelper-spring-boot-starter</artifactId>

    <version>1.2.5</version>

</dependency>

配置分页插件,打开application.properties,添加如下配置信息:

#分页插件

pagehelper.helper-dialect=postgresql

如果需要通过url自动识别方言,配置dialectAlias参数,具体的实现类和pg的映射保持一致即可,根据不同的pagehelper版本来定。以pagehelper-5.1.10为例,如下:

pagehelper:

dialectAlias: kingbase8=com.github.pagehelper.dialect.helper.HsqldbDialect

  • Mybatis 使用自动返回主键功能

该功能使用在V7仅支持insert语句

建表语句,要求表含有主键,且主键自增:

create table t_user (id int identity primary key,username text,password text,sex boolean);

在mapper文件里配置:

xml 复制代码
<!-- useGeneratedKeys:(仅对 insert 有用)这会告诉 MyBatis 使用 JDBC 的getGeneratedKeys方法来取出由数据内部生成的主键。默认值: false。 -->

<!--keyProperty:(仅对 insert有用)标记一个属性, MyBatis 会通过 getGeneratedKeys或者通过 insert 语句的 selectKey 子元素设置它的值。默认:不设置。 -->

         <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">

                   insert into t_user (username,password,sex) values

                   (#{username},#{password},#{sex})

         </insert>

**注意:**如果使用tk-mybatis提供的mapper接口,V7需要mapper包的版本在3.4.0及以上,否则使用update相关的接口时,会报"不能返回generatedkeys或没有指定返回"的错误。

  • Mybatis配置databaseId

    ini 复制代码
    <databaseIdProvider type="DB_VENDOR">
    
        <property name="KingbaseES" value="kingbase"/>
    
    </databaseIdProvider>

    SELECT * FROM product3

  • Mybatis使用匿名块插入语句报错

Mybatis中使用begin insert ...;insert...; end;格式的语句插入数据,报无法识别的GBK编码:'0x00'或者指定了连接参数prepareThreshold=-1报Can't change resolved type for param:1 from 1043 to 25.该问题属于plsql问题需要升级数据库版本。

在升级数据库版本后,如果出现类型转换错误,则使用强转(例如?::bytea)把其转换为对应类型,出现该错误的原因为匿名块无法识别oid绑定类型为0的参数,会将其默认识别为text,传给下层时无法转换为对应类型,就会报错。特别地,如果字段类型为二进制,如bytea、blob,如果参数内容有数据库无法识别的编码的话,转换成text就会报无法转换的编码错误,此时指定连接参数bytestype=bytea即可。

  • Mybatis使用ScriptRunner执行含plsql的sql脚本报错
  1. ScriptRunner默认按照自定义的分隔符每行执行,分隔符默认为分号,如果sql脚本中包含plsql语句,按照分号分割出来的语句是不正确的,所以可以使用setDelimiter(String)来设置自定义的分隔符,如设置分隔符为"/",则sql脚本中的每条语句后都添加"/",ScriptRunner将会按照此对语句进行分割,连接KingbaseES时,普通语句之间无需使用分隔符,驱动会对普通语句进行分割;
  2. 或者可以通过runner.setSendFullScript(true);设置将sql脚本一次发送,但是由于驱动不会对包含plsql的多语句进行分割,所以会报"无法插入多条命令到一个准备好的语句中",此时指定jdbc连接参数preferQueryMode=simple走简单查询报文即可。
  • Mybatis使用游标的注册方式

<select id="selectTempManualDataTest" statementType="CALLABLE"> {#{out_return,mode=OUT,javaType=ResultSet,jdbcType=OTHER, resultMap=tempMap} = call proc_aaaaa() } </select>

注意:

  1. jdbcType只能设置为OTHER,不能设置为CURSOR,Mybatis的CURSOR的值为-10,是OracleCURSOR的值,不是Types.REF_CURSOR的值,我们不支持;

  2. 如果没有设置javaType的类型,返回值的类型为ResultSet,如果设置了返回值的类型为ResultSet,则返回值为List对象。

  • Mybatis写json类型示例

    建表:

    create table t_json(id serial,content json);

    实体类:

    package com.test.entity; public class JsonEntity { private int id; private Object fcontent;

    public int getId() { return id; } public void setId( int id) { this.id = id; }

    public Object getContent() { return fcontent; } public void setContent(Object b) { this.fcontent = b; }

    @Override public String toString() { return "id=" + this.id ; } }

    JsonTypeHandler.java

    package com.test.handler;

    import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException;

    import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType;

    import com.test.utils.JsonUtil;

    // 继承自BaseTypeHandler 使用Object是为了让JsonUtil可以处理任意类型 public class JsonTypeHandler extends BaseTypeHandler {

    @Override public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {

    vbscript 复制代码
        ps.setString(i, JsonUtil.stringify(parameter));

    }

    @Override public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {

    return JsonUtil.parse(rs.getString(columnName), Object.class); }

    @Override public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {

    return JsonUtil.parse(rs.getString(columnIndex), Object.class); }

    @Override public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {

    return JsonUtil.parse(cs.getString(columnIndex), Object.class); }

    }

    JsonUtil.java

    package com.test.utils;

    import java.io.OutputStream; import java.text.SimpleDateFormat;

    import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.annotate.JsonFilter; import org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter; import org.codehaus.jackson.map.ser.impl.SimpleFilterProvider; import org.springframework.core.annotation.AnnotationUtils; import org.codehaus.jackson.map.SerializationConfig;

    public class JsonUtil {

    private static Log log = LogFactory.getLog(JsonUtil.class);

    private static ObjectMapper objectMapper = null;

    static {

    ini 复制代码
        objectMapper = new ObjectMapper();
    
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-mm-dd"));
        objectMapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
        objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.setFilters(new SimpleFilterProvider().setFailOnUnknownId(false));

    }

    /* public static JsonUtil getInstance() {

    ini 复制代码
        if (instance == null) {
            synchronized (JsonUtil.class) {
                if (instance == null) {
                    instance = new JsonUtil();
                }
            }
        }
    
        return instance;
    }
    */

    public static String stringify(Object object) {

    try { return objectMapper.writeValueAsString(object); } catch (Exception e) { log.error(e.getMessage(), e); }

    return null; }

    public static String stringify(Object object, String... properties) {

    try { return objectMapper .writer(new SimpleFilterProvider().addFilter(AnnotationUtils.getValue( AnnotationUtils.findAnnotation(object.getClass(), JsonFilter.class)).toString(), SimpleBeanPropertyFilter.filterOutAllExcept(properties))) .writeValueAsString(object); } catch (Exception e) { log.error(e.getMessage(), e); }

    return null; }

    public static void stringify(OutputStream out, Object object) {

    try { objectMapper.writeValue(out, object); } catch (Exception e) { log.error(e.getMessage(), e); } }

    public static void stringify(OutputStream out, Object object, String... properties) {

    try { objectMapper.writer(new SimpleFilterProvider().addFilter( AnnotationUtils.getValue(AnnotationUtils.findAnnotation(object.getClass(), JsonFilter.class)).toString(), SimpleBeanPropertyFilter.filterOutAllExcept(properties))).writeValue(out, object); } catch (Exception e) { log.error(e.getMessage(), e); } }

    public static T parse(String json, Class clazz) {

    if (json == null || json.length() == 0) { return null; }

    try { return objectMapper.readValue(json, clazz); } catch (Exception e) { log.error(e.getMessage(), e); }

    return null; }

    }

    映射文件:
    select * from {name} select \* from t_json where id=#{id} insert into t_json (content) values ((#{fcontent, typeHandler=com.test.handler.JsonTypeHandler})::json) update t_json set content=(#{fcontent, typeHandler=com.test.handler.JsonTypeHandler})::json where t_json.id=#{id} delete from {name}

  • Mybatis 一次插入参数过多问题

  • KES数据库一次最大能绑定的参数个数是32767,如果一次绑定参数个数超过就会报错

  • 下面是一个一次绑定N个参数的SQL配置:

sql 复制代码
<insert id="insertBatch" parameterType="java.util.Map">

INSERT INTO testtable(

a,b,c,d

)

<foreach collection="list" item="item" separator="union all">

SELECT 

#{item.parma1,jdbcType=BIGINT},

#{item.parma2,jdbcType=INTEGER},

#{item.parma3,jdbcType=INTEGER},

#{item.parma4,jdbcType=VARCHAR},

FROM DUAL

</foreach>

</insert>
  • 当list很大时,就会拼接一个超过最大参数个数限制的SQL,这里提供两种思路解决类似问题;
    1:不使用参数绑定,使用参数注入,把#换成$,就没有参数个数限制,性能和当前基本一致。
  • 2:依然使用参数绑定,但SQL需要改写为常规Insert的SQL,需要使用ExecutorType.BATCH模式,批处理性能更好,具体例子:
ini 复制代码
SqlSession session = sessionFactory.openSession(ExecutorType.BATCH);

for (Model model : list) {

    session.insert("insertStatement", model);

}

session.flushStatements();

2. KES与MyBatis-Plus

2.1 Mybaits-Plus简介

  • MyBatis-Plus 是基于 MyBatis 的增强工具库,旨在简化 MyBatis 的开发流程,提供更便捷的数据库访问操作。它是对 MyBatis 的扩展,提供了一系列的增强功能和便利的开发特性。
  • MyBatis-Plus 的主要特点包括:
  • 简化的 CRUD 操作:MyBatis-Plus 提供了一套简化的 API,可以通过少量的代码实现常见的增删改查操作,无需手动编写 SQL 语句。
  • 自动生成代码:MyBatis-Plus 提供了代码生成器,可以根据数据库表结构自动生成实体类、Mapper 接口和 XML 配置文件,减少了手动编写重复代码的工作量。
  • Lambda 表达式支持:MyBatis-Plus 支持使用 Lambda 表达式进行条件构造,可以更直观地编写查询条件,提高代码的可读性和维护性。
  • 分页查询支持:MyBatis-Plus 提供了方便的分页查询功能,可以轻松地进行分页查询操作。
  • 逻辑删除支持:MyBatis-Plus 支持逻辑删除,可以通过配置实现软删除功能,将删除操作转换为更新操作,保留数据的完整性。
  • 自动填充字段:MyBatis-Plus 支持自动填充字段,可以在插入或更新操作时自动填充指定的字段,如创建时间、更新时间等。
  • 乐观锁支持:MyBatis-Plus 提供了乐观锁的支持,可以通过版本号或时间戳等方式实现并发控制,避免数据冲突。
  • 总的来说,MyBatis-Plus 是一个功能强大、易于使用的 MyBatis 增强工具库,它简化了数据库访问的开发流程,提供了诸多便利的特性和功能,使得开发人员可以更高效地进行数据库操作。

2.2 Mybatis-Plus支持的驱动形态

  • 框架名称
  • 方言包
  • 支持的驱动形态
  • Mybatis-Plus
  • KES、PG形态

2.3 Mybatis-Plus框架结构

2.4 Mybatis-Plus配置说明

  • Mybatis-Plus的jar包可以从官方网站下载,Mybatis-Plus所使用的JDBC包kingbase8-8.6.0.jar位于$KINGBASE_HOME/Interface/jdbc目录下。使用时将Mybatis-Plus包和JDBC包导入到项目的Libraries中并定义相关配置项即可。

2.4.1配置Spring配置文件

  • 配置MapperScan:

    <property name="basePackage" value="com.baomidou.mybatisplus

    .Mybatis_plus_Sample.mapper" />

  • 调整SqlSessionFactory为Mybatis-Plus的SqlSessionFactory:

    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension

    .spring.MybatisSqlSessionFactoryBean">

    <property name="typeAliasesPackage" value="com.baomidou.mybatisplus

    .Mybatis_plus_Sample.entity" />

    <bean id="paginationInterceptor"

    class="com.baomidou.mybatisplus.extension.plugins

    .PaginationInterceptor">

  • 配置实体类

    @TableName(value = "tb_employee") /* 指定表名 */

    public class Employee {

    /* value与数据库主键列名一致,若实体类属性名与表主键列名一致可省略value */

    @TableId(value = "id", type = IdType.AUTO) /* 指定自增策略 */

    private Integer id;

    /* 若没有开启驼峰命名,或者表中列名不符合驼峰规则,可通过该注解 */

    /* 指定数据库表中的列名,exist标明数据表中有没有对应列 */

    @TableField(value = "last_name", exist = true)

    private String lastName;

    private String email;

    private boolean gender;

    private Integer age;

    private Date date;

    public Integer getId() {

    return id;

    }

    public void setId(Integer id) {

    this.id = id;

    }

    public String getLastName() {

    return lastName;

    }

    public void setLastName(String lastName) {

    this.lastName = lastName;

    }

    public String getEmail() {

    return email;

    }

    public void setEmail(String email) {

    this.email = email;

    }

    public boolean isGender() {

    return gender;

    }

    public void setGender(boolean gender) {

    this.gender = gender;

    }

    public Integer getAge() {

    return age;

    }

    public void setAge(Integer age) {

    this.age = age;

    }

    public Date getDate() {

    return date;

    }

    public void setDate(Date date) {

    this.date = date;

    }

    @Override

    public String toString() {

    return "Employee [id=" + id + ", lastName=" + lastName + ",

    email=" + email + ", gender=" + gender +", age=" + age + ",

    date=" + date + "]";

    }

    }

  • 定义Mapper接口

    @Mapper

    public interface EmplopyeeDao extends BaseMapper {

    }

  • 在Java中进行表的增删改查操作

    @RunWith(SpringJUnit4ClassRunner.class)

    @ContextConfiguration({ "classpath:spring/spring-dao.xml" })

    public class test {

    @Autowired

    private DataSource dataSource;

    @Test

    public void testDataSource() throws SQLException {

    System.out.println(dataSource.getConnection());

    }

    @Autowired

    private EmplopyeeDao emplopyeeDao;

    @Test

    public void testInsert() {

    Employee employee = new Employee();

    employee.setLastName("tom");

    employee.setEmail("dfbb@163.com");

    employee.setGender(false);

    employee.setAge(22);

    employee.setDate(new Date(System.currentTimeMillis()));

    emplopyeeDao.insert(employee);

    /* mybatisplus会自动把当前插入对象在数据库中的id写回到该实体中 */

    System.out.println(employee.getId());

    }

    @Test

    public void testUpdate() {

    Employee employee = new Employee();

    employee.setId(1);

    employee.setLastName("更新测试");

    /* 根据id进行更新,没有传值的属性就不会更新 */

    emplopyeeDao.updateById(employee);

    /* 根据id进行更新,没传值的属性就更新为null */

    emplopyeeDao.update(employee, null);

    }

    @Test

    public void testSelectById() {

    Employee employee = emplopyeeDao.selectById(2);

    System.out.println(employee.toString());

    }

    @Test

    public void testSelect() {

    Map columnMap = new HashMap();

    /* 写表中的列名 */

    columnMap.put("last_name", "更新测试");

    columnMap.put("gender", false);

    List employees = emplopyeeDao.selectByMap(columnMap);

    System.out.println(employees.size());

    }

    @Test

    public void testSelectByPage() {

    IPage employees = emplopyeeDao.selectPage(new Page(1, 5),

    new QueryWrapper().between("age", 18, 50).eq("gender",

    false).eq("last_name", "更新测试"));

    System.out.println(employees);

    }

    @Test

    public void testDeleteById() {

    System.out.println(emplopyeeDao.deleteById(1));

    }

    @Test

    public void testDelete() {

    Map columnMap = new HashMap();

    columnMap.put("gender", false);

    columnMap.put("age", 18);

    emplopyeeDao.deleteByMap(columnMap);

    }

    @Test

    public void testSelectByPage1() {

    Integer[] ints = { 1, 18, 19, 20, 21, 22, 23, 24, 25 };

    IPage employees = emplopyeeDao.selectPage(new Page(1, 5),

    new QueryWrapper().between("age", 18, 50).eq("gender",

    false).eq("last_name", "更新测试").in(true,

    "age", Arrays.asList(ints)));

    System.out.println(employees.toString());

    System.out.println(employees.getTotal());

    System.out.println(employees.getPages());

    System.out.println(employees.getRecords());

    }

    }

2.5 注意事项

  • Mybatis-Plus2.x和Mybatis-Plus3.x的包结构不同,注意引用时的包路径的区别;
  • KingbaseES适配Mybatis-Plus时,由于Mybatis-Plus无法识别KingbaseES数据库类型,故在相关配置中需将其配置成postgresql,如:
  • 在使用分页插件时,配置方言类型为postgresql示例:
xml 复制代码
<property name="plugins">

<array>

<!-- 分页插件配置 -->

<bean id="paginationInterceptor" class="com.baomidou.mybatisplus

.extension.plugins.PaginationInterceptor">

<property name="dialectType" value="postgresql" />

</bean>

</array>

</property>
  • KingbaseES适配Mybatis-Plus时,由于Mybatis-Plus无法识别KingbaseES数据库类型,故在相关配置中需将其配置成postgresql,如:
  • 在使用分页插件时,配置方言类型为postgresql示例:
xml 复制代码
<property name="plugins">

<array>

<!-- 分页插件配置 -->

<bean id="paginationInterceptor" class="com.baomidou.mybatisplus

.extension.plugins.PaginationInterceptor">

<property name="dialectType" value="postgresql" />

</bean>

</array>

</property>
相关推荐
在努力的前端小白11 分钟前
Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
java·数据库·spring boot·文本处理·敏感词过滤·dfa算法·组件开发
未来之窗软件服务13 分钟前
自建知识库,向量数据库 (九)之 量化前奏分词服务——仙盟创梦IDE
数据库·仙盟创梦ide·东方仙盟·自建ai·ai分词
冒泡的肥皂3 小时前
MVCC初学demo(一
数据库·后端·mysql
.Shu.4 小时前
Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
数据库·redis·架构
薛晓刚7 小时前
当MySQL的int不够用了
数据库
SelectDB技术团队8 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光8 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓12018 小时前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql
染落林间色8 小时前
达梦数据库-实时主备集群部署详解(附图文)手工搭建一主一备数据守护集群DW
数据库·sql
颜颜yan_8 小时前
企业级时序数据库选型指南:从传统架构向智能时序数据管理的转型之路
数据库·架构·时序数据库