人大金仓数据库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>
相关推荐
CoderIsArt1 小时前
Redis的三种模式:主从模式,哨兵与集群模式
数据库·redis·缓存
师太,答应老衲吧3 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
Channing Lewis4 小时前
salesforce case可以新建一个roll up 字段,统计出这个case下的email数量吗
数据库·salesforce
毕业设计制作和分享5 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
ketil275 小时前
Redis - String 字符串
数据库·redis·缓存
Hsu_kk6 小时前
MySQL 批量删除海量数据的几种方法
数据库·mysql
编程学无止境6 小时前
第02章 MySQL环境搭建
数据库·mysql
knight-n6 小时前
MYSQL库的操作
数据库·mysql
包饭厅咸鱼7 小时前
QML----复制指定下标的ListModel数据
开发语言·数据库
生命几十年3万天8 小时前
redis时间优化
数据库·redis·缓存