Mybatis一:理论知识和增删改查

1 概述

1.1 简介

  1. mybatis是个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注SQL语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
  2. mybatis通过xml或annotation的方式将要执行的各种statement配置起来,并通过java对象和statement中SQL的动态参数进行映射生成最终执行的SQL语句,最后由mybatis框架执行SQL并将结果映射为java对象并返回。
  3. 采用ORM(Object Relational Mappging对象关系映射)思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。

1.2 核心对象

  • 在使用MyBatis框架时,主要涉及两个核心对象:SqlSessionFactory和SqlSession,它们在MyBatis框架中起着至关重要的作用,图解如下,下面进行详解。

  1. SqlSessionFactory

    1. SqlSessionFactory是单个数据库映射关系经过编译后的内存镜像,主要作用是创建SqlSession。

    2. SqlSessionFactory是线程安全的,一旦被创建整个应用执行期间都会存在。如果多次的创建同一个数据库的SqlSessionFactory,那么数据库资源很容易被耗尽,因此在构建SqlSessionFactory实例时,一般使用单例模式。

      // 创建SqlSessionFactory代码
      InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      
  2. SqlSession

    1. SqlSession是应用程序与持久层之间执行交互操作的一个单线程对象,是线程不安全的。SqlSession使用完后,要及时关闭它。

    2. SqlSession方法如下(了解即可,IDEA中可以点击ctrl+鼠标左键查看)

      // 注:若使用mybatis的传统开发方式(即编写接口的实现类)需要用到以下方法,但不推荐使用此方式,推荐用xml或annotation
      public interface SqlSession extends Closeable {
      
          // statement是在配置文件中,<select>元素的id
          <T> T selectOne(String statement); 
          <T> T selectOne(String statement, Object parameter);
          <E> List<E> selectList(String statement);
          <E> List<E> selectList(String statement, Object parameter);
          // rowBounds:用于分页的参数对象
          <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds); 
          // 下面这些查询不常用,用到在学
          <K, V> Map<K, V> selectMap(String var1, String var2);
          <K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
          <K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);
          <T> Cursor<T> selectCursor(String var1);
          <T> Cursor<T> selectCursor(String var1, Object var2);
          <T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);
          void select(String var1, Object var2, ResultHandler var3);
          void select(String var1, ResultHandler var2);
          void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
          //下面增删改(共六个方法)返回值是SQL语句所影响的行数
          int insert(String statement); 
          int insert(String statement, Object parameter);
          int update(String statement); 
          int update(String statement, Object parameter);
          int delete(String var1);  
          int delete(String var1, Object var2);
          
          void commit();
          void commit(boolean var1);
          void rollback();
          void rollback(boolean var1);
          
          List<BatchResult> flushStatements();
          void close();
          void clearCache();
          Configuration getConfiguration();
          <T> T getMapper(Class<T> var1);
          Connection getConnection();
      }
      

1.3 mybatis配置文件

  • 主要元素【注:必须按照以下顺序配置,否则会报错(可以缺,但不能乱)

  1. <properties> 元素

    <!-- 在resources下创建db.properties文件,然后使用<properties>标签引入 -->
    <properties resource="路径"/>
    
  2. <settings> 元素

    <!-- 用于改变mybatis运行时的行为,例如开启二级缓存、开启延迟加载等 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 其他配置略,若需要时再去查询 -->
    </settings>
    
  3. <typeAliases> 元素

    1. typeAliases用于定义别名,减少全限定类名的冗余。

    2. alias属性的属性值就是自定义的别名,可以代替com.li.domain.User使用在mybatis文件中的任何位置。如果alias属性省略,mybatis会默认将类名首字母小写后的名称作为别名。

      <!-- 使用样例如下 -->
      <typeAliases>
          <typeAlias alias="User" type="com.li.domain.User"/>
      </typeAliases>
      
  4. <environments> 元素

    1. 该元素可以配置多种数据源,即配置多种数据库。

    2. environments标签的default属性用于指定默认的环境。environment是environments的子标签,可以定义多个(即配置多种数据库);transactionManager是environment的子标签,用于配置事务(有JDBC和MANAGED两种);dataSource也是environment的子标签,用于配置数据源(有UNPOOLED、POOLED常用、JNDI三种)。

    3. 样例

      <environments default="mysql">
          <environment id="mysql">
              <transactionManager type="JDBC"></transactionManager>
              <dataSource type="POOLED">
                  <property name="driver" value="com.mysql.jdbc.Driver"/>
                  <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
                  <property name="username" value="root"/>
                  <property name="password" value="123456"/>
              </dataSource>
          </environment>
      </environments>
      
  5. <mappers> 元素

    1. 该元素用于指定mybatis映射文件的位置,有以下四种配置方式

    2. 注意路径中的"/"与".",一般前两种比较常用(资源用斜杠,类用点)

      <!-- 四种引入方式代码,经测试均可用 -->
      <mappers>
          <!--使用类路径引入-->
          <mapper resource="mapper/UserMapper.xml"/>
          <!--使用接口类引入-->
          <mapper class="mapper.UserMapper"/>
          <!--使用本地文件路径引入(注意前面要加file:\\\),三个斜杠第一个是转义符-->
          <mapper url="file:\\\D:\IDEA\code\mybatisCURD\src\main\resources\mapper\UserMapper.xml"/>
          <!--使用包名引入-->
          <package name="mapper"/>
      </mappers>
      
  6. 其他元素不太常用,略。等用到时再总结。

1.4 mybatis映射文件

  • 主要元素

  1. insert、delete、update、select元素【insert的元素中的特殊属性用法(其他元素略)】

  2. resultMap

    1. <resultMap> 元素表示结果映射集,是MyBatis中最重要也是最强大的元素。它的主要作用是定义映射规则、级联的更新、定义类型转化器等。

    2. 包含的子元素如下

      <resultMap id="" type="">
          <!-- 1. 构造方法,idArg即id参数,标记结果作为id;arg即注入到构造方法的一个普通结果-->
          <constructor>
              <idArg/>
              <arg/>
          </constructor>
          <!-- ☆2. 指定主键 -->
          <id/>
          <!-- ☆3. 注入到字段或者JavaBean属性的普通结果-->
          <result/>
          <!-- ☆4. 用于一对一关联-->
          <association property=""/>
          <!-- ☆5. 用于一对多关联-->
          <collection property=""/>
          <!-- 6. 使用结果值来决定使用哪个结果映射,case子标签表示基于某些值的结果映射-->
          <discriminator javaType="">
              <case value=""></case>
          </discriminator>
      </resultMap>
      
    3. 样例

      <resultMap id="userResultMap" type="domain.User">
          <!-- 2. 指定主键 -->
          <id property="id" column="t_id"/>
          <!-- 3. 注入到字段或者JavaBean属性的普通结果-->
          <result property="username" column="t_username"/>
          <result property="birthday" column="t_birthday"/>
          <result property="sex" column="t_sex"/>
          <result property="address" column="t_address"/>
      </resultMap>
      <!-- 此时要用resultMap标签,而不是以前的resultType-->
      <select id="findAllByResultMap" resultMap="userResultMap">
              select * from t_user
      </select>
      

2 入门程序

-- SQL脚本如下
CREATE TABLE `t_user` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` datetime default NULL COMMENT '生日',
  `sex` char(1) default NULL COMMENT '性别',
  `address` varchar(256) default NULL COMMENT '地址',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `t_user`(`id`,`username`,`birthday`,`sex`,`address`) 
values  (41,'张三','2018-02-27 17:47:08','男','北京'),
	(42,'小明','2018-03-02 15:09:37','女','北京金燕龙'),
	(43,'小明','2018-03-04 11:34:34','女','北京金燕龙'),
	(45,'李四','2018-03-04 12:04:06','男','北京金燕龙'),
	(46,'王五','2018-03-07 17:37:26','男','北京'),
	(48,'赵六','2018-03-08 11:44:00','女','北京修正');

2.1 xml方式

  • 普通maven工程,结构图如下

  1. 依赖

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
    </dependency>
    
  2. 实体类

    package cn.pojo;
    import lombok.ToString;
    import java.util.Date;
    
    @ToString
    public class User {
        private Integer id;
        private String username;
        private Date birthday;
        private String six;
        private String address;
    }
    
  3. 持久层

    package cn.dao;
    import cn.pojo.User;
    import java.util.List;
    
    public interface UserDao {
        List<User> findAll();
        /**
         * 注:在实际发开中,都是越简单越好,故不采用写Dao实现类的方式,使用xml或annotation都行。
         * 虽然不推荐写Dao实现类,但是mybatis是支持写实现类的。
         */
    }
    
  4. 配置

    # resources/log4j.properties,把下面内容直接粘贴过去即可
    
    # Set root category priority to INFO and its only appender to CONSOLE.
    #log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
    log4j.rootCategory=debug, CONSOLE, LOGFILE
    # Set the enterprise logger category to FATAL and its only appender to CONSOLE.
    log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
    # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
    # LOGFILE is set to be a File appender using a PatternLayout.
    log4j.appender.LOGFILE=org.apache.log4j.FileAppender
    log4j.appender.LOGFILE.File=d:\axis.log
    log4j.appender.LOGFILE.Append=true
    log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
    
    <!-- 持久层接口实现文件,必须和持久层接口在相同的包中【位置要求,可见上面截图】 -->
    <!-- copy 时namespace和resultType记得两处都要改 -->
    
    <?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="cn.dao.UserDao">
        <!--id要与UserDao中的方法名一致-->
        <select id="findAll" resultType="cn.pojo.User">
            select *
            from t_user
        </select>
    </mapper>
    
    <!-- resources/mybatis-config.xml,mybatis核心配置文件 -->
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <!-- mybatis的主配置文件 -->
    <configuration>
        <!-- 配置环境 -->
        <environments default="mysql">
            <!-- 配置mysql的环境-->
            <environment id="mysql">
                <!-- 配置事务的类型-->
                <transactionManager type="JDBC"></transactionManager>
                <!-- 配置数据源(连接池) -->
                <dataSource type="POOLED">
                    <!-- 配置连接数据库的4个基本信息 -->
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://192.168.192.130:3306/test?serverTimezone=CTT"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
        <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
        <mappers>
            <mapper resource="dao/UserDao.xml"/>
        </mappers>
    </configuration>
    
  5. 运行

    package cn;
    
    import cn.dao.UserDao;
    import cn.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    public class App {
        public static void main(String[] args) throws IOException {
            //1.读取配置文件
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            //2.创建SqlSessionFactory工厂
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            //3.使用工厂生产SqlSession对象
            SqlSession session = factory.openSession();
            //4.使用SqlSession创建Dao接口的代理对象
            UserDao userDao = session.getMapper(UserDao.class);
            //5.使用代理对象执行方法
            List<User> users = userDao.findAll();
            for (User user : users) {
                System.out.println(user);
            }
            //6.释放资源
            session.close();
            inputStream.close();
        }
        /**
         * 结果
         * User(id=41, username=张三, birthday=Tue Feb 27 17:47:08 CST 2018, six=null, address=北京)
         * User(id=42, username=小明, birthday=Fri Mar 02 15:09:37 CST 2018, six=null, address=北京金燕龙)
         * User(id=43, username=小明, birthday=Sun Mar 04 11:34:34 CST 2018, six=null, address=北京金燕龙)
         * User(id=45, username=李四, birthday=Sun Mar 04 12:04:06 CST 2018, six=null, address=北京金燕龙)
         * User(id=46, username=王五, birthday=Wed Mar 07 17:37:26 CST 2018, six=null, address=北京)
         * User(id=48, username=赵六, birthday=Thu Mar 08 11:44:00 CST 2018, six=null, address=北京修正)
         */
    }
    

2.2 annotation方式

  • 普通maven工程,结构图如下

  1. 依赖

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
    </dependency>
    
  2. 实体类

    • 同 xml 方式实体类
  3. 持久层

    package cn.dao;
    import cn.pojo.User;
    import org.apache.ibatis.annotations.Select;
    
    import java.util.List;
    
    public interface UserDao {
        @Select("select * from t_user")
        List<User> findAll();
    }
    
  4. 配置

    1. log4j.properties 日志配置同上面 xml 方式,略

    2. mybatis-config.xml 配置如下

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
          <environments default="mysql">
              <environment id="mysql">
                  <transactionManager type="JDBC"></transactionManager>
                  <dataSource type="POOLED">
                      <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                      <property name="url" value="jdbc:mysql://192.168.192.130:3306/test?serverTimezone=CTT"/>
                      <property name="username" value="root"/>
                      <property name="password" value="root"/>
                  </dataSource>
              </environment>
          </environments>
          <mappers>
              <!--<mapper resource="dao/UserDao.xml"/>-->
              <mapper class="cn.dao.UserDao"/>
          </mappers>
      </configuration>
      
  5. 测试

    package cn.dao;
    import cn.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    public class UserDaoTest {
    
        @Test
        public void findAll() throws IOException {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = factory.openSession();
            UserDao userDao = session.getMapper(UserDao.class);
            List<User> users = userDao.findAll();
            for (User user : users) {
                System.out.println(user);
            }
            session.close();
            inputStream.close();
        }
    
        /**
         * 结果
         * User(id=41, username=张三, birthday=Tue Feb 27 17:47:08 CST 2018, six=null, address=北京)
         * User(id=42, username=小明, birthday=Fri Mar 02 15:09:37 CST 2018, six=null, address=北京金燕龙)
         * User(id=43, username=小明, birthday=Sun Mar 04 11:34:34 CST 2018, six=null, address=北京金燕龙)
         * User(id=45, username=李四, birthday=Sun Mar 04 12:04:06 CST 2018, six=null, address=北京金燕龙)
         * User(id=46, username=王五, birthday=Wed Mar 07 17:37:26 CST 2018, six=null, address=北京)
         * User(id=48, username=赵六, birthday=Thu Mar 08 11:44:00 CST 2018, six=null, address=北京修正)
         */
    }
    

3 增删改查

  1. SQL脚本同上面的入门程序,略

  2. #{}${} 的对比

    #{} ${}
    一个占位符 一个sql串
    自动进行java类型和jdbc类型转换 不进行jdbc类型转换
    防止sql注入 无法防止sql注入
    可以接收简单类型值或pojo属性值,
    如果parameterType传输单个简单类型值,
    #{}括号中可以是value或其它名称。
    可以接收简单类型值或pojo属性值,
    如果parameterType传输单个简单类型值,
    ${}括号中只能是value
    1. #{}相当于JDBC中的"?",而 "#{id}"表示该占位符待接收参数的名称为id。
    2. 拼接sql串时若想防止sql注入,可用mysql中的concat()函数。eg. select * from t_customer where username like concat('%',#{value},'%')

3.1 xml方式

  • 普通maven工程,结构图如下

  • 整个项目基于上面入门程序的xml方式改造,因此下文仅展示不同部分的代码,相同部分略

  1. 实体类

    package cn.pojo;
    import lombok.Data;
    import java.util.Date;
    
    @Data
    public class User {
        // 特意加个前缀user于列名不同,主要是用于测试resultMap映射
        private Integer userId;
        private String userName;
        private String userAddress;
        private String userSex;
        private Date userBirthday;
    }
    
    package cn.pojo;
    import lombok.Data;
    
    @Data
    public class FindPojo {
        User user;
    }
    
  2. 持久层

    package cn.mapper;
    import cn.pojo.FindPojo;
    import cn.pojo.User;
    import java.util.List;
    
    /**
     * mapper层即持久层,与以前的dao层一样。
     * 也可以写dao.UserDao,配置文件写成UserDao.xml
     * 但是mybatis提供的是mapper标签,因此用mapper居多,
     * 也可以写成dao层,两者完全一样
     */
    public interface UserMapper {
        void addUser(User user);
    
        void deleteUser(Integer id);
    
        void updateUser(User user);
    
        //包装类参数(注意xml中文件参数写法)
        List<User> findByPojo(FindPojo pojo);
    
        List<User> findAll();
    }
    
  3. 配置

    <?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="cn.mapper.UserMapper">
        <insert id="addUser" parameterType="cn.pojo.User">
            INSERT INTO t_user (username, birthday, sex, address)
            VALUES (#{userName}, #{userBirthday}, #{userSex}, #{userAddress})
        </insert>
    
        <!-- UserMapper接口中定义的方法 void deleteUser(int id);当参数只有一个时,id=#{id} 这个占位符可以随便填。-->
        <!--比如写可以改成 void deleteUser(int uid) 、 id=#{aaa} (只起个占位作用) -->
        <delete id="deleteUser" parameterType="Integer">
            DELETE
            FROM t_user
            WHERE id = #{id}
        </delete>
    
        <update id="updateUser" parameterType="cn.pojo.User">
            UPDATE t_user
            SET username = #{userName},
                address  = #{userAddress},
                sex      = #{userSex},
                birthday = #{userBirthday}
            WHERE id = #{userId}
        </update>
    
        <!-- 包装类参数,注意写法,是user.userName而不是仅userName -->
        <!-- 解决属性与列不对应问题:法1:别名  法2:resultMap -->
        <!-- findByPojo用别名方法映射列,下面的findAll用resultMap方法,推荐使用resultMap-->
        <select id="findByPojo" parameterType="cn.pojo.FindPojo" resultType="cn.pojo.User">
            SELECT ID       AS userId,
                   USERNAME AS userName,
                   BIRTHDAY AS userBirthday,
                   SEX      AS userSex,
                   ADDRESS  AS userAddress
            FROM t_user
            WHERE USERNAME LIKE #{user.userName}
        </select>
    
        <select id="findAll" resultMap="userMap">
            SELECT *
            FROM t_user
        </select>
    
        <resultMap id="userMap" type="cn.pojo.User">
            <!-- 主键字段的对应 -->
            <id property="userId" column="id"/>
            <!--非主键字段的对应-->
            <result property="userName" column="username"/>
            <result property="userAddress" column="address"/>
            <result property="userSex" column="sex"/>
            <result property="userBirthday" column="birthday"/>
        </resultMap>
    </mapper>
    
  4. 测试

    package cn.mapper;
    
    import cn.pojo.FindPojo;
    import cn.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Date;
    import java.util.List;
    
    public class UserMapperTest {
    
        /**
         * 注:增删改提交事务的方法都放在 @After public void destory()方法中
         * 别没看全以为不用提交事务!
         */
        private InputStream inputStream;
        private SqlSession sqlSession;
        private UserMapper userMapper;
    
        @Before
        public void init() throws IOException {
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = factory.openSession();
            userMapper = sqlSession.getMapper(UserMapper.class);
        }
    
        @After
        public void destory() throws IOException {
            //释放资源前提交事务,写在destory()内可以减少代码冗余,免得都写
            sqlSession.commit();
            //6.释放资源
            sqlSession.close();
            inputStream.close();
        }
    
        @Test
        public void addUser() {
            User user = new User();
            user.setUserName("张良");
            user.setUserBirthday(new Date());
            user.setUserSex("男");
            user.setUserAddress("郑州");
            userMapper.addUser(user);
        }
    
        @Test
        public void deleteUser() {
            userMapper.deleteUser(48);
        }
    
        @Test
        public void updateUser() {
            User user = new User();
            user.setUserName("孙悟空");
            user.setUserBirthday(new Date());
            user.setUserSex("男");
            user.setUserAddress("水帘洞");
            user.setUserId(46);
            userMapper.updateUser(user);
        }
    
        @Test
        public void findByPojo() {
            FindPojo pojo = new FindPojo();
            User user = new User();
            user.setUserName("%小%");
            pojo.setUser(user);
            List<User> users = userMapper.findByPojo(pojo);
            System.out.println(users);
        }
    
        @Test
        public void findAll() {
            List<User> users = userMapper.findAll();
            for (User user : users) {
                System.out.println(user);
            }
        }
    }
    

3.2 annotation方式

常用注解

序号 注解 说明
1 @Insert
2 @Delete
3 @Update
4 @Select
5 @Result 实现结果集封装
6 @Results 可以与@Result一起使用,封装多个结果集
7 @ResultMap 实现引用@Results定义的封装
8 @One 实现一对一结果集封装
9 @Many 实现一对多结果集封装
10 @SelectProvider 实现动态SQL映射
11 @CacheNamespace 实现注解二级缓存的使用

复杂注解映射说明

  1. @Results注解代替的是<resultMap>标签,该注解可以使用单个@Result,也可以使用@Result集合。
    1. 样例: @Results(@Result()) 或 @Results({@Result(),@Result()})
  2. @Result注解代替的是<id><result>标签,属性如下
    1. id : 是否是主键字段
    2. property : 需要装配的属性名
    3. column : 数据库的列名
    4. one : 需要使用@One注解 ( @Result(one=@One) )
    5. many : 需要使用@Many注解 ( @Result(many = @Many) )
  3. @One注解(一对一)代替的是<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
    1. 其select属性指定用来多表查询的sqlMapper。
    2. 样例: @Result(property="",column=" ",one=@One(select="")
  4. @Many注解(一对多)代替的是<collection>标签,是多表查询的关键,在注解中用来指定子查询返回对象集合。
    1. 注意:聚集元素用来处理“一对多”的关系。需要指定映射的Java实体类的属性,属性的javaType(一般为ArrayList)但是注解中可以不定义。
    2. 样例: @Result(property="",column="",many=@Many(select=""))

代码

  • 普通maven工程,结构图如下。

  • 整个项目基于上面增删改查xml方式改造,因此下文仅展示不同部分的代码,相同部分略

  1. 持久层

    package cn.mapper;
    import cn.pojo.FindPojo;
    import cn.pojo.User;
    import org.apache.ibatis.annotations.*;
    import java.util.List;
    
    /**
     * 个人建议:短sql用注解,太长的sql写在xml文件中,否则方法上一大堆太丑
     * 注:定义了@Results(id = "userMap")之后,以后可以用@ResultMap("userMap")进行引用,
     * 例如下面的findByPojo方法可以不写SQL别名,添加注解@ResultMap("userMap")即可
     * 定义@Results的方法(即findAll方法)无需使用,若是加上会编译报错!!!
     */
    public interface UserMapper {
    
        @Insert("INSERT INTO t_user (username, birthday, sex, address)" +
                "VALUES (#{userName}, #{userBirthday}, #{userSex}, #{userAddress})")
        void addUser(User user);
    
        @Delete("DELETE FROM t_user WHERE id = #{id}")
        void deleteUser(Integer id);
    
        @Update("UPDATE t_user  SET username = #{userName},  address = #{userAddress}," +
                "sex = #{userSex}, birthday = #{userBirthday}  WHERE id = #{userId}")
        void updateUser(User user);
    
    
        @Select("SELECT ID AS userId, USERNAME AS userName, BIRTHDAY AS userBirthday," +
                "SEX AS userSex, ADDRESS AS userAddress FROM t_user WHERE USERNAME LIKE #{user.userName}")
        List<User> findByPojo(FindPojo pojo); // 包装类参数
    
        @Select("SELECT * FROM t_user")
        @Results(id = "userMap",
                value = {
                        @Result(property = "userId", column = "id"),
                        @Result(property = "userName", column = "username"),
                        @Result(property = "userAddress", column = "address"),
                        @Result(property = "userSex", column = "sex"),
                        @Result(property = "userBirthday", column = "birthday")
                }
        )
        List<User> findAll();
    }
    
  2. 配置 mybatis-config.xml

    <mappers>
        <mapper class="cn.mapper.UserMapper"/>
    </mappers>
    
  3. 测试

    • 同上面增删改查xml方式代码,略。
posted @ 2021-11-18 09:35  lkf-newlife  阅读(75)  评论(0编辑  收藏  举报