Mybatis学习(二):Mybatis入门教程和简单应用

MyBatis-Flex入门教程:轻量高效的MyBatis增强框架 MyBatis-Flex入门摘要 MyBatis-Flex是一个轻量高效的MyBatis增强框架,在保留MyBatis灵活性的同时,提供了更强大的查询构建器、动态表名和多租户支持等企业级特性。相比MyBatis-Plus,它具有性能卓越(执行效率提升5-10倍)、轻量无依赖、功能丰富等优势。 使用步骤包括:添加依赖、配置数据源、创建实体类与Mapper接口,支持基础CRUD和链式查询。进阶功能涵盖动态表名、逻辑删除、多表联查和字段权限控制。最佳实践建议使用代码生成器、优化批量操作和SQL监控。 对比MyBa 阅读详情

Mybatis学习(二):Mybatis入门教程和简单应用

前言

接上一篇Mybatis学习(一):基础概念和简单自定义持久层框架demo

一、 Mybatis简介

1.1 ORM简介

ORM(Object/Relation Mapping):对象—关系映射的缩写。

      ORM完成面向对象的编程语言到数据库的映射。ORM把关系数据库包装成面向对象的模型。采用orm框架后,应用程序不再直接访问数据库,而是用面向对象的方式操作持久化对象,orm框架本身把这些操作转变成数据库底层SQL操作。

1.2 Mybatis简介

      Mybatis是一款优秀的基于ORM的半自动化轻量级持久层框架,它支持定制化SQL、存储过程和高级映射。Mybatis可以用简单的xml或者注解来配置和映射原生类型、接口和实体类。

二、基本应用

2.1 demo入门应用

2.1.1 MyBatis官方地址

MyBatis官方地址:https://mybatis.org/mybatis-3/zh/index.html
在这里插入图片描述

2.1.2 环境搭建

新建一个maven项目

2.1.2.1 引入相关maven依赖
<!--mybatis依赖-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.20</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
</dependency>
2.1.2.2 本地数据库新建user用户表

在这里插入图片描述

2.1.2.3 新建user实体类
public class User {

    private int id;
    private String name;
    private String password;

    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 String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
2.1.2.4 新建UserMapper映射配置文件UserMapper.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="com.learn.dao.UserDao">
    <!--namespace : 名称空间:与id组成sql的唯一标识
        resultType: 表明返回值类型-->

    <!--查询用户-->
    <select id="findAll" resultType="com.learn.pojo.User">
       select * from user
    </select>
</mapper>
2.1.2.5 新增MyBatis核心配置文件sqlMapConfig.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:运行环境-->
    <environments default="dev">
        <environment id="dev">
            <!--当前事务交由JDBC进行管理-->
            <transactionManager type="JDBC"/>
            <!--当前使用mybatis提供的连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?serverTimezone=UTC&amp;characterEncoding=utf8&amp;useUnicode=true&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="xijian"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射配置文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>

</configuration>

注意: 驱动class注意mysql版本的区别(8.0以上是"com.mysql.cj.jdbc.Driver")

2.1.2.6 测试
@org.junit.Test
    public void test1() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.生产sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();// 默认开启一个事务,但是该事务不会自动提交
        //在进行增删改操作时,要手动提交事务
        //4.sqlSession调用方法:查询所有selectList  查询单个:selectOne 添加:insert  修改:update 删除:delete
        List<User> users = sqlSession.selectList("com.learn.dao.UserDao.findAll");
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

测试结果:
在这里插入图片描述

2.1.3 简单的CRUD栗子

2.1.3.1 查询

前边的例子已经展示过查询了

2.1.3.2 新增
  • 映射文件UserMapper.xml中新增插入方法:

    <insert id="add" parameterType="com.learn.pojo.User">
        insert into user values(#{id},#{name},#{password})
    </insert>
    
  • 编写测试方法:

        @org.junit.Test
    public void test2() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.生产sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();// 默认开启一个事务,但是该事务不会自动提交
        //4.sqlSession调用方法:查询所有selectList  查询单个:selectOne 添加:insert  修改:update 删除:delete
        User user = new User();
        user.setId(2);
        user.setName("lisi");
        user.setPassword("123456");
        int insert = sqlSession.insert("com.learn.dao.UserDao.add", user);
        System.out.println(insert);
        //手动提交事务
        sqlSession.commit();
        sqlSession.close();
    }
    
  • 测试结果
    在这里插入图片描述
    注意:

  1. 在映射文件中插入使用的是insert标签;
  2. 在映射文件中要使用parameterType属性指定插入的数据类型;
  3. 在映射文件的具体插入sql语句中#{实体类的属性名称}的方式引用入参;
  4. 使用sqlSession操作时,新增需要注意手动提交事务。
2.1.3.3 修改
  • 映射文件UserMapper.xml中新增修改方法:

    <update id="update" parameterType="com.learn.pojo.User">
        update user set name=#{name},password=#{password} where id=#{id}
    </update>
    
  • 编写测试方法:

       @org.junit.Test
    public void test3() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.生产sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();// 默认开启一个事务,但是该事务不会自动提交
        //4.sqlSession调用方法:查询所有selectList  查询单个:selectOne 添加:insert  修改:update 删除:delete
        User user = new User();
        user.setId(2);
        user.setName("lisi2");
        user.setPassword("123456");
        int update = sqlSession.update("com.learn.dao.UserDao.update", user);
        //手动提交事务
        sqlSession.commit();
        sqlSession.close();
        System.out.println(update);
    }
    
  • 测试结果
    在这里插入图片描述

2.1.3.4 删除
  • 映射文件UserMapper.xml中新增删除方法:

     <delete id="delete" parameterType="int">
        delete from user where id=#{id}
    </delete>
    
  • 编写测试方法:

      @org.junit.Test
    public void test4() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.生产sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();// 默认开启一个事务,但是该事务不会自动提交
        //4.sqlSession调用方法:查询所有selectList  查询单个:selectOne 添加:insert  修改:update 删除:delete
        int delete = sqlSession.delete("com.learn.dao.UserDao.delete", 2);
        //手动提交事务
        sqlSession.commit();
        sqlSession.close();
        System.out.println(delete);
    }
    
  • 测试结果
    在这里插入图片描述

2.1.4 Dao层实现的方式

2.1.4.1 传统的实现方式(实现类调用SqlSession)
  1. 新建UserDao接口类
    public interface UserDao {
    
        List<User> findAll();
    }
    
  2. 新建UserDaoImpl接口实现类
    public class UserDaoImpl implements UserDao {
    
        @Override
        public List<User> findAll() throws Exception {
            //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            //2.解析了配置文件,并创建了sqlSessionFactory工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //3.生产sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();// 默认开启一个事务,但是该事务不会自动提交
            //在进行增删改操作时,要手动提交事务
            //4.sqlSession调用方法:查询所有selectList  查询单个:selectOne 添加:insert  修改:update 删除:delete
            List<User> users = sqlSession.selectList("com.learn.dao.UserDao.findAll");
            sqlSession.close();
            return users;
        }
    }
    
  3. 测试
        @org.junit.Test
        public void test5() throws Exception {
            UserDao userDao = new UserDaoImpl();
            List<User> userList = userDao.findAll();
            System.out.println(userList);
        }
    
  4. 测试结果
    在这里插入图片描述
2.1.4.2 代理的实现方式
  1. 新建UserMapper接口类
    public interface UserMapper{
    
        List<User> findAll();
    }
    
  2. 修改UserMapper.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="com.learn.dao.UserMapper">
        <!--namespace : 名称空间:与id组成sql的唯一标识
            resultType: 表明返回值类型-->
    
        <!--查询用户-->
        <select id="findAll" resultType="com.learn.pojo.User">
           select * from user
        </select>
    
        <insert id="add" parameterType="com.learn.pojo.User">
            insert into user values(#{id},#{name},#{password})
        </insert>
    
        <update id="update" parameterType="com.learn.pojo.User">
            update user set name=#{name},password=#{password} where id=#{id}
        </update>
    
        <delete id="delete" parameterType="int">
            delete from user where id=#{id}
        </delete>
    </mapper>
    
  3. 测试
        @org.junit.Test
        public void test6() throws Exception {
            //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            //2.解析了配置文件,并创建了sqlSessionFactory工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //3.生产sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();// 默认开启一个事务,但是该事务不会自动提交
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<User> users = userMapper.findAll();
            sqlSession.close();
            System.out.println(users);
        }
    
  4. 测试结果
    在这里插入图片描述

注意:

  • Mapper.xml映射文件里的namespace必须与mappe接口的全限定名保持一致;
  • Mapper接口的每个方法名必须和Mapper.xml映射文件里的每个statement的id属性的值保持一致;
  • Mapper接口里方法的入参必须和mapper.xml映射文件里每个sql的parameterType类型保持一致;
  • Mapper接口里方法的返回值必须和mapper.xml映射文件里每个sql的resultType类型保持一致;

2.2 配置文件属性说明

2.2.1 XML配置文件(sqlMapConfig.xml)

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
      • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)
2.2.1.1 properties(属性)
2.2.1.1.1 如何设置属性
  1. 在典型的 Java 属性文件中配置这些属性
  2. 在 properties 元素的子元素中设置

例子:

	<properties resource="config.properties">
        <property name="username" value="dev"/>
        <property name="password" value="dev"/>
    </properties>

    <!--environments:运行环境-->
    <environments default="dev">
        <environment id="dev">
            <!--当前事务交由JDBC进行管理-->
            <transactionManager type="JDBC"/>
            <!--当前使用mybatis提供的连接池-->
            <dataSource type="POOLED">
                <!--<property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="jdbc:mysql:///mybatis?serverTimezone=UTC&amp;characterEncoding=utf8&amp;useUnicode=true&amp;useSSL=false"/>
                <!--<property name="username" value="root"/>-->
                <!--<property name="password" value="xijian"/>-->
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

说明:

  1. 在外部配置文件中配置的属性或者在properties 元素的子元素中设置的属性,在整个配置文件中我们可以用来替换需要动态配置的属性值;
  2. Java中SqlSessionFactoryBuilder类提供了对应的api方法,可以在Java代码中配置属性。
    	public SqlSessionFactory build(Reader reader, Properties properties) {
            //。。。。。
        }
        public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        	//。。。。。
        }
    
2.2.1.1.2 MyBatis 属性加载顺序

注意:
如果一个属性在不只一个地方进行了配置,那么MyBatis 将按照下面的顺序来加载:

  • 首先读取在 properties 元素体内指定的属性;
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性;
  • 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
2.2.1.1.3 占位符指定一个默认值

从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值。例如:
<property name="username" value="${username:ut_user}"/>
如果属性 ‘username’ 没有被配置,‘username’ 属性的值将为 ‘ut_user’。

  1. 这个特性默认是关闭的。要启用这个特性,需要添加一个特定的属性来开启这个特性。
    <properties resource="config.properties">
      <!-- 启用默认值特性 -->
      <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> 
    </properties>
    
  2. 如果在属性名中使用了 “:” 字符(如:db:username),或者在 SQL 映射中使用了 OGNL 表达式的三元运算符(如: ${tableName != null ? tableName : ‘global_constants’}),就需要设置特定的属性来修改分隔属性名和默认值的字符。
    <properties resource="org/mybatis/example/config.properties">
    	<!-- 修改默认值的分隔符 -->
    	<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> 
    </properties>
    
    <dataSource type="POOLED">
    	<!-- ... -->
    	<property name="username" value="${db:username?:ut_user}"/>
    </dataSource>
    
2.2.1.2 settings(设置)

一个配置完整的 settings 元素的示例如下:

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

具体说明参考:Mybatis官方文档

2.2.1.3 typeAliases(类型别名)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

  1. 举个栗子:

        <typeAliases>
            <typeAlias alias="user" type="com.learn.pojo.User"/>
        </typeAliases>
    
  2. 也可以指定一个包下所有的Bean类

        <typeAliases>
            <!--<typeAlias alias="user" type="com.learn.pojo.User"/>-->
            <package name="com.learn.pojo"/>
        </typeAliases>
    

    com.learn.pojo包下所有的bean类如果没有注解,那么默认使用首字母小写的非限定类名来作为它的别名。有注解,则别名为其注解值。

    @Alias("user")
    public class User {
    	//。。。。
    }
    
2.2.1.4 typeHandlers(类型处理器)

MyBatis在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类。

MyBatis中有很多默认支持的类型处理器,具体参考:官方文档

我们可以重写已有的类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。
具体做法为:
        实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 并且可以(可选地)将它映射到一个 JDBC 类型。

  1. 创建自定义的类型处理器j
    // ExampleTypeHandler.java
    @MappedJdbcTypes(JdbcType.VARCHAR)
    public class ExampleTypeHandler extends BaseTypeHandler<String> {
    
      @Override
      public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
      }
    
      @Override
      public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
      }
    
      @Override
      public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
      }
    
      @Override
      public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
      }
    }
    
  2. 在mybatis-config.xml(mybatis的配置文件)中增加配置
    <typeHandlers>
      <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
    </typeHandlers>
    

注意:

  1. 在类型处理器的配置元素(typeHandler 元素)上增加一个 javaType 属性(比如:javaType=“String”)MyBatis 可以得知该类型处理器处理的 Java 类型;在类型处理器的配置元素上增加一个 jdbcType 属性(比如:jdbcType=“VARCHAR”)指定与其关联的 JDBC 类型列表。

  2. 在类型处理器的类上增加一个 @MappedTypes 注解指定与其关联的 Java 类型列表;在类型处理器的类上增加一个 @MappedJdbcTypes 注解指定与其关联的 JDBC 类型列表。

     ==上述的1,2两种配置方式,1的优先级高于2。==
    
  3. 我们可以通过指定包名的方式让 MyBatis 帮我们查找类型处理器

    <!-- mybatis-config.xml -->
    <typeHandlers>
      <package name="org.mybatis.example"/>
    </typeHandlers>
    

    注意在使用自动发现功能的时候,只能通过注解方式来指定 JDBC 的类型。

2.2.1.5 objectFactory(对象工厂)

每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现。

// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
  public Object create(Class type) {
    return super.create(type);
  }
  public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
    return super.create(type, constructorArgTypes, constructorArgs);
  }
  public void setProperties(Properties properties) {
    super.setProperties(properties);
  }
  public <T> boolean isCollection(Class<T> type) {
    return Collection.class.isAssignableFrom(type);
  }
 }

在Mybatis的配置文件中增加对应配置

<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
	<property name="someProperty" value="100"/>
</objectFactory>

objectFactory 元素体中定义的属性会被传递给 setProperties方法

2.2.1.6 plugins(插件)

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

@Intercepts({@Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class})})
public class ExamplePlugin implements Interceptor {

    private Properties properties = new Properties();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // implement pre processing if need
        Object returnObject = invocation.proceed();
        // implement post processing if need
        return returnObject;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

在Mybatis配置文件中新增配置:

    <plugins>
        <plugin interceptor="com.learn.interceptor.ExamplePlugin">
            <property name="someProperty" value="100"/>
        </plugin>
    </plugins>
2.2.1.7 environments(环境配置)

示例:

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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>

注意一些关键点:

  • 默认使用的环境 ID(比如:default=“development”)。
  • 每个 environment 元素定义的环境 ID(比如:id=“development”)。
  • 事务管理器的配置(比如:type=“JDBC”)。
  • 数据源的配置(比如:type=“POOLED”)。
    默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。
2.2.1.7.1 transactionManager(事务管理器)

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
    <transactionManager type="MANAGED">
      <property name="closeConnection" value="false"/>
    </transactionManager>
    
2.2.1.7.2 dataSource(数据源)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):

  • UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。UNPOOLED 类型的数据源仅仅需要配置以下 5 种属性:

    • driver – 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。
    • url – 这是数据库的 JDBC URL 地址。
    • username – 登录数据库的用户名。
    • password – 登录数据库的密码。
    • defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
    • defaultNetworkTimeout – 等待数据库操作完成的默认网络超时时间(单位:毫秒)。

    作为可选项,你也可以传递属性给数据库驱动。只需在属性名加上“driver.”前缀即可,例如:
    driver.encoding=UTF8
    这将通过 DriverManager.getConnection(url, driverProperties) 方法传递值为 UTF8 的 encoding 属性给数据库驱动。

  • POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
    除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:

    • poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10
    • poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
    • poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
    • poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
    • poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过poolMaximumIdleConnections 与 poolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
    • poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
    • poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
    • poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
  • JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。这种数据源配置只需要两个属性:

    • initial_context – 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。
    • data_source – 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。

    和其他数据源配置类似,可以通过添加前缀“env.”直接把属性传递给 InitialContext。比如:env.encoding=UTF8这就会在 InitialContext 实例化时往它的构造方法传递值为 UTF8 的 encoding 属性。

2.2.1.7.3 databaseIdProvider(数据库厂商标识)

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。

MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。

为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:

<databaseIdProvider type="DB_VENDOR" />

databaseIdProvider 对应的 DB_VENDOR 实现会将 databaseId 设置为 DatabaseMetaData#getDatabaseProductName() 返回的字符串。 由于通常情况下这些字符串都非常长,而且相同产品的不同版本会返回不同的值,你可能想通过设置属性别名来使其变短:

<databaseIdProvider type="DB_VENDOR">
  <property name="SQL Server" value="sqlserver"/>
  <property name="DB2" value="db2"/>
  <property name="Oracle" value="oracle" />
</databaseIdProvider>

在提供了属性别名时,databaseIdProvider 的 DB_VENDOR 实现会将 databaseId 设置为数据库产品名与属性中的名称第一个相匹配的值,如果没有匹配的属性,将会设置为 “null”。 在这个例子中,如果 getDatabaseProductName() 返回“Oracle (DataDirect)”,databaseId 将被设置为“oracle”。

我们可以通过实现接口 org.apache.ibatis.mapping.DatabaseIdProvider 并在 mybatis-config.xml 中注册来构建自己的 DatabaseIdProvider:

public interface DatabaseIdProvider {
  default void setProperties(Properties p) { // 从 3.5.2 开始,该方法为默认方法
    // 空实现
  }
  String getDatabaseId(DataSource dataSource) throws SQLException;
}
2.2.1.8 mappers(映射器)

告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:

  1. 使用相对于类路径的资源引用
    <mappers>
      	<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
    </mappers>
    
  2. 使用完全限定资源定位符(URL)
    	<mappers>
    		<mapper url="file:///var/mappers/AuthorMapper.xml"/>
    	</mappers>
    
  3. 使用映射器接口实现类的完全限定类名
    <mappers>
    	<mapper class="org.mybatis.builder.AuthorMapper"/>
    </mappers>
    
  4. 将包内的映射器接口实现全部注册为映射器
    <mappers>
    	<package name="org.mybatis.builder"/>
    </mappers>
    

2.2.2 XML映射文件(Mapper.xml)

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • cache – 该命名空间的缓存配置。
  • cache-ref – 引用其它命名空间的缓存配置。
  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
  • sql – 可被其它语句引用的可重用语句块。
  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。
2.2.2.1 select标签

Select 元素的属性

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap对外部 resultMap 的命名引用
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
fetchSize这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetTypeFORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
resultOrdered这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false。
resultSets这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。
2.2.2.2 insert, update 和 delete标签

数据变更语句 insert,update 和 delete 的实现非常接近:

<insert
  id="insertAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  keyProperty=""
  keyColumn=""
  useGeneratedKeys=""
  timeout="20">

<update
  id="updateAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">

<delete
  id="deleteAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">

Insert, Update, Delete 元素的属性:

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyProperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。

注意:

  1. 如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性就 OK 了。
  2. 对于不支持自动生成主键列的数据库和可能不支持自动生成主键的 JDBC 驱动,MyBatis 有另外一种方法来生成主键。
    <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>
    
    selectKey 元素的属性:
    属性描述
    keyPropertyselectKey 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称。
    keyColumn返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称。
    resultType结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。
    order可以设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它首先会生成主键,设置 keyProperty 再执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。
    statementType和前面一样,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 类型的映射语句,分别代表 Statement, PreparedStatement 和 CallableStatement 类型。
2.2.2.3 sql标签

这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。

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

<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>

也可以在 include 元素的 refid 属性或内部语句中使用属性值,例如:

<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>
2.2.2.4 参数
2.2.2.4.1 字符串替换

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:ORDER BY ${columnName}。

提示:
用这种方式接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击。

2.2.2.5 结果映射

在没有显式的指定 resultMap时,可以使用resultType 属性指定,将所有的列映射到 HashMap的键上。

当resultType 属性指定到JavaBean时,MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。

我们也可以显式使用外部的 resultMap,然后在引用它的语句中设置 resultMap 属性就行了。

<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>

注意:
高级结果映射 请跳转 官方文档—结果映射

2.2.2.6 自动映射

在简单的场景下,MyBatis 可以为你自动映射查询结果。但如果遇到复杂的场景,你需要构建一个结果映射。我们可以混合使用这两种策略。

例如:

<resultMap id="userResultMap" type="User">
  <result property="password" column="hashed_password"/>
</resultMap>

<select id="selectUsers" resultMap="userResultMap">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password
  from some_table
  where id = #{id}
</select>

例子中,id 和 userName 列将被自动映射,hashed_password 列将根据配置进行映射。

有三种自动映射等级:

  • NONE - 禁用自动映射。仅对手动映射的属性进行映射。
  • PARTIAL - 对除在内部定义了嵌套结果映射(也就是连接的属性)以外的属性进行映射
  • FULL - 自动映射所有属性。
    默认值是PARTIAL,这是有原因的。当对连接查询的结果使用 FULL 时,连接查询会在同一行中获取多个不同实体的数据,因此可能导致非预期的映射。

无论设置的自动映射等级是哪种,你都可以通过在结果映射上设置 autoMapping属性来为指定的结果映射设置启用/禁用自动映射。

<resultMap id="userResultMap" type="User" autoMapping="false">
  <result property="password" column="hashed_password"/>
</resultMap>
2.2.2.7 缓存
2.2.2.7.1 设置缓存

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

这个简单语句的效果如下:

  • 映射语句文件中的所有 select 语句的结果将会被缓存。
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

提示:
缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

  1. 可用的清除策略有:默认的清除策略是 LRU。
    • LRU – 最近最少使用:移除最长时间不被使用的对象。
    • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
    • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
  2. flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
  3. size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
  4. readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
2.2.2.7.2 使用自定义缓存
<cache type="com.domain.something.MyCustomCache">
  <property name="cacheFile" value="/tmp/my-custom-cache.tmp"/>
</cache>
  1. type 属性指定的类必须实现 org.apache.ibatis.cache.Cache 接口,且提供一个接受 String 参数作为 id 的构造器。
  2. 为了对自定义的缓存进行配置,只需要简单地自定义的缓存实现中添加公有的 JavaBean属性,然后通过 cache 元素传递属性值,例如,上边的例子将在自定义的缓存实现上调用一个名为 setCacheFile(String file) 的方法。
  3. 也可以使用占位符(如 ${cache.file}),以便替换成在配置文件属性中定义的值。

提示:

  1. 上一节中对缓存的配置(如清除策略、可读或可读写等),不能应用于自定义缓存。
  2. 缓存的配置和缓存实例会被绑定到 SQL 映射文件的命名空间中。 因此,同一命名空间中的所有语句和缓存将通过命名空间绑定在一起。 每条语句可以自定义与缓存交互的方式,或将它们完全排除于缓存之外,这可以通过在每条语句上使用两个简单属性来达成。 默认情况下,语句会这样来配置:
    <select ... flushCache="false" useCache="true"/>
    <insert ... flushCache="true"/>
    <update ... flushCache="true"/>
    <delete ... flushCache="true"/>
    
2.2.2.7.3 cache-ref

对某一命名空间的语句,只会使用该命名空间的缓存进行缓存或刷新。 但你可能会想要在多个命名空间中共享相同的缓存配置和实例。要实现这种需求,你可以使用 cache-ref 元素来引用另一个缓存。

<cache-ref namespace="com.someone.application.data.SomeMapper"/>

2.3 动态 SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

2.3.1 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>

在 where 后的条件语句中根据多个参数动态判断时,使用多个if标签完成。

2.3.2 choose、when、otherwise 标签

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

<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>

在上面的例子中:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就使用featured = 1的条件。

2.3.3 trim、where、set 标签

  1. where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
  2. 如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
      ...
    </trim>
    
  3. 用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如下边两种等价的语句:
    <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>
    
    <trim prefix="SET" suffixOverrides=",">
      ...
    </trim>
    

2.3.4 foreach 标签

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 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>

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。

提示:
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。

  • 当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。
  • 当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

2.3.5 bind 标签

bind元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:

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

2.3.6 多数据库支持

如果配置了databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId”的变量来为不同的数据库构建特定的语句。比如下面的例子:

<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>

2.3.7 动态 SQL 中的插入脚本语言

MyBatis 从 3.2 版本开始支持插入脚本语言,这允许你插入一种语言驱动,并基于这种语言来编写动态 SQL 查询语句。
可以通过实现以下接口来插入一种语言:

public interface LanguageDriver {
  ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
  SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
  SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
}

实现自定义语言驱动后,你就可以在 mybatis-config.xml 文件中将它设置为默认语言:

<typeAliases>
  <typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
</typeAliases>
<settings>
  <setting name="defaultScriptingLanguage" value="myLanguage"/>
</settings>

或者也可以使用 lang 属性为特定的语句指定语言:

<select id="selectBlog" lang="myLanguage">
  SELECT * FROM BLOG
</select>

或者在mapper 接口上添加 @Lang 注解:

public interface Mapper {
  @Lang(MyLanguageDriver.class)
  @Select("SELECT * FROM BLOG")
  List<Blog> selectBlog();
}

提示:
前面看到的所有 xml 标签都由默认 MyBatis 语言提供,而它由语言驱动 org.apache.ibatis.scripting.xmltags.XmlLanguageDriver(别名为xml)所提供。

三、彩蛋

本篇笔者描述了一下MyBatis的demo入门应用,配置文件属性说明及动态SQL。
下一篇笔者将讲解传统XML配置开发、注解开发、MyBatis缓存、MyBatis插件。

MyBatis 入门教程详解 阅读详情

相关推荐

QST QMC5883L —— 经典磁传感器的生存指南与替代预案

本文聚焦于QST旗下经典三轴磁力计 QMC5883L,解析其技术渊源、核心特性及当前面临的停产风险。结合真实应用场景提供续命方案与选型建议,为依赖该芯片的开发团队争取过渡时间窗口期。文章包含实测数据对比、生命周期管理策略及潜在替代方案拆解。存续价值判断✔️ 现有产品设计无需大幅改动即可延续生命;❌ 新项目采用将面临更高的维护成本;⚠️ 建议在6个月内完成技术路线切换。#磁传感器 #嵌入式开发 #供应链管理 #QST #QMC5883L。

2501_93066786的博客 998

mybatis学习文档

mybatis-9.28 环境: JDK1.8 mysql 8.0.16 maven3.6.1 IDEA 回顾: JDBC mysql jave基础 Maven junit 1.简介 1.1 什么是mybatis ​ mybatis是支持普通SQL查询、存储过程和高级映射的优秀持久层框架。 MyBatis 是一款优秀的持久层框架 支持自定义 SQL、存储过程以及高级映射 MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作 MyBatis 可

weixin_47356044的博客 3312

2017阿里内推笔试题--算法工程师(运筹优化)

2017阿里内推笔试题–算法工程师(运筹优化)题目沐哲是一个菜鸟仓库的一个拣货员,但他有非常个怪异的习惯。每次拣货的重量都要比之前拣的一个轻,每次拣到货后都可以得到1块钱,沐哲想知道这样最多能赚多少钱 32 34 7 33 21 2 13 12 3 11 26 36 16 30 22 1 24 14 20 23 25 5 19 29 27 15 9 17 31 4 6 18 8 10 3

shawpan的专栏 1万+

什么是MyBatis

MyBatis是什么?为什么要用MyBatis?一文搞定!!!

雷东宸的博客 3万+

AT32F435/437开发实战:把SD卡变成U盘的完整指南(含源码解析)

本文提供了基于AT32F435/437微控制器将SD卡改造为U盘的完整实战指南。通过深入解析USB MSC协议与SDIO驱动的协同工作原理,详细介绍了硬件设计要点、软件架构融合、核心源码解析以及从编译到文件传输的完整调试流程,帮助开发者实现可靠的大容量存储设备扩展。

weixin_29159127的博客 410

【ESP32】SPI SRAM memory test fail。External RAM failed memory test!

log日志报错如下:这两条报错信息表明外部 SPI SRAM(静态随机存取存储器)的内存测试失败。

weixin_56217406的博客 1024

【超详细】MyBatis详解

Mybatis

weixin_48373085的博客 2万+

思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)

思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)

2301_81256766的博客 1261

Mybatis详解

1.mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。2.mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。

realmew的博客 1万+

python基础之语言发展历史

博主简介:原互联网大厂tencent员工,网安巨头Venustech员工,阿里云开发社区专家博主,微信公众号java基础笔记优质创作者,csdn优质创作博主,创业者,知识共享者,欢迎关注,点赞,收藏。 目录一、前言二、发展历史1、Python是一种面向对象的解释型编程语言2、Python常被称为胶水语言3、Python由Guido开发4、Python连续多年入选编程语言TOP105、Python的发展历史三、总结 一、前言   由于Python语言的简洁性、易读性以及可扩展性,它在网络爬虫、数据分析、.

jiankang66的博客 3348

多标签图像分类:标签依赖关系建模的最新论文解读与实战应用

多标签图像分类:标签依赖关系建模的最新论文解读与实战应用 ,人工智能,计算机视觉,大模型,AI,本文解读了最新相关论文,包括基于图神经网络(GCN)的ML-GCN方法,通过构建标签相关矩阵建模依赖关系;区域潜在语义依赖的RLSD模型,定位关键区域并利用RNN建模语义依赖;以及语义图表示学习的SSGRL框架,结合语义解耦与交互模块。通过实战应用,展示了基于PyTorch的ML-GCN模型实现,包括图像特征提取、标签依赖建模及训练评估流程,为多标签图像分类提供了有效解决方案。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 18万+

Mybatis(完整详解,包括增删改查)

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

Java技术加油站的博客 1万+

【异常】Coze/扣子 Workflow 调用报 4200 错误深度解析

Coze API 的。

奶爸的编程之路,也就一周冷个三天 302

二、【MyBatis】 MyBatis入门与简单使用

Object Relation Mapping 对象关系映射。对象指的是JAVA对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在JAVA对象和数据库的关系模型之间建立一种对象个关系,比如用一个Java的User类,去对应数据库中的一张表goyeer_user类,类中的属性和表中的列一一对应。User类就对应goyeer_userk类中的一行数据。我们可以使用Mybatis的注解开发一些简单映射语句,这样可以是代码显得更加简介。

记录总结工作过往 744

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

MyBatis 学习二

多表查询是在企业中必不可少的,无论多么简单的项目里都会出现多表查询操作。因为只要是关系型数据库,在设计表时都需要按照范式进行设计,为了减少数据冗余,都会拆成多个表。当需要表中数据时,在进行联合查询。在MySQL学习时,知道表之间关系分为:一对一、一对多、多对多。这三种关系又细分为单向和双向。如果学习的是Hibernate框架,必须要严格区分开表之间的关系,然后才能使用Hibernate框架。但是在MyBatis框架中只有两种情况:当前表对应另外表是一行数据还是多行数据。

wangqiang996的博客 774

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

mybatis的简单应用

mybatis的简单整合maven

qq_55162766的博客 1556

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

spring boot 、mybatis-plus、shiro整合入门教程(二)——mybatis-plus常用操作

接续上一篇,spring boot 、mybatis-plus、shiro整合入门教程(一)——mybatis-plus代码生成器 项目中的数据库表设计如下: 菜单管理页面功能:新增、修改、删除、查询 新增代码如下: SysMenuController类的代码如下: @Resource private SysMenuServiceImpl sysMenuService; /*...

u011915230的专栏 990

mybatis学习(二)之手写mybatis

提供一个无参数构造方法,再提供一个build方法,该build方法要返回SqlSessionFactory对象/*** SqlSessionFactory对象构建器* @author 老杜*//*** 创建构建器对象*//*** 获取SqlSessionFactory对象* 该方法主要功能是:读取godbatis核心配置文件,并构建SqlSessionFactory对象* @param inputStream 指向核心配置文件的输入流。

weixin_57342469的博客 1450

MyBatis 和 MyBatis-Plus的简单分析

MyBatis 是一个基于 Java 的持久层框架,它通过 SQL 语句与数据库进行交互,允许开发者手动编写 SQL,并通过映射文件将其与 Java 对象进行关联。相比于 Hibernate 等 ORM 框架,MyBatis 提供了更多的灵活性,因为它让开发者对 SQL 进行更直接的控制。MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,它在 MyBatis 的基础上进行了一些封装,简化了开发者的工作量。

hhaimm的博客 870

MyBatis和Spring整合简单实现

- 1 向SqlSessionFactory索要小服务-->-- 日志--><settings>-- 向SqlSessionFactory申请自定义类型在SQl映射文件中别名服务实际开发方式,为某个包下所有类来申请别名,别名就是当前的类名且可以忽略字母大小写使用-->-- 2 为SqlSessionFactory中内置数据库连接池指定连接四要素【将使用druid提供的连接池,替代sqlSessionFactory内置连接池】-->

m0_75127592的博客 1809

Mybatis概述及简单应用

文章目录Ⅰ.mybatis概述Ⅱ.工作原理1.主配置文件(sqlConfig.xml)2.数据库映射文件(Mapper.xml)Ⅲ.基础操作CRUD1.查2.增3.删4.改Ⅳ.映射文件绑定接口Ⅴ.MybatisGenerator Ⅰ.mybatis概述 Ⅱ.工作原理 1.主配置文件(sqlConfig.xml) 2.数据库映射文件(Mapper.xml) Ⅲ.基础操作CRUD 1.查 2.增 3.删 4.改 Ⅳ.映射文件绑定接口 Ⅴ.MybatisGenerator ...

ifffff的博客 618

Spring Boot学习日志二<SpringBoot 结合MyBatis读取MySQL 数据>

通过这次的作业,我了解并掌握了如何使用数据库去创建表并添加数据,并将表连接到程序中去。并且初始接触并学习到了controller、service、mapper、domain 包及对应的JAVA程序的相关知识。虽然途中遇到的两个问题花了我很长时间去解决,但是这两个问题提升了我的独立思考能力和解决问题的能力。

HUMGAMING的博客 2309

Mybatis 入门教程

Mybatis 入门教程 1、参考资料 2020年IDEA版黑马Java就业班-进阶篇(Mybatis、Spring、SpringMVC、Maven、springboot和项目等等 项目地址:Oneby / mybatis-learn 2、Mybatis 入门案例 2.1、Mybatis 简介 原始 jdbc 操作的缺点 1、查询操作 注册数据库驱动 ➡️ 从数据库连接池中获取一个 Connection 对象 ➡️ 从 Connection 对象中获取 PreparedStatement 对象(需要

Oneby的博客 1671

MyBatis 学习记录(二)之mybatis基本使用方法

mybatis的基本使用方法

LB_Wuyanzu的博客 1168

Mybatis-Flex的简单入门,Mybatis-Flex和其它框架对比

选择哪一个框架应该基于项目的具体需求和技术栈的选择。如果你追求极致的性能并且可以接受较小的社区支持,那么 MyBatis-Flex 可能是一个不错的选择;而如果你更看重社区支持和丰富的插件生态,那么 MyBatis-Plus 则可能更适合你。

qq_65597930的博客 2439

MyBatis入门教程

本文介绍了MyBatis原生的使用方法,包括准备工作、快速开始、绑定SQL语句等步骤。首先创建数据库表并添加依赖,然后创建实体类和持久层接口。通过XML或注解方式配置SQL语句,构建SqlSessionFactory并调用mapper接口方法。文章重点演示了两种SQL绑定方式(XML和注解)的使用及注意事项,同时解决了包名创建错误等常见问题。适合需要了解MyBatis原生使用的开发者参考。

沐雨橙风ιε的博客 778
上一篇: 分布式定时任务—xxl-job学习(四)——调度中心web页面端api调用源码分析
下一篇: Mybatis学习(三):Mybatis注解开发、缓存使用和插件使用的深度分析
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RabbitsInTheGrass

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值