Mybatis学习笔记

Mybatis

mybatis为持久层(Dao层)的使用框架

通过xml或注解的方式将statement配置起来

将java对象和statement中的sql参数进行映射生成最终执行的sql语句

一、原始jdbc

1.1、原始jdbc查询操作

  1. 查询:

    //注册驱动
    Class.forName("com.mysql.jsbc.Driver");
    //获得连接
    Connection conn = DriverManager.getConnection("jdbc:mysql:///test","root","root");
    //获得statement
    PreparedStatement sta = conn.prepareStatement("select * from user");
    //执行查询
    ResultSet rs = sta.executeQuery();
    //遍历结果
    while(rs.next()){
        //数据操作
    }
    //释放资源
    rs.close();
    sta.cloae();
    conn.close();
    
  2. 插入

    //模拟实体对象
    User user = new User();
    user.setId("1");
    user.setName("xxx");
    ----------------------------------------------------------------
    ----------------------------------------------------------------   
    //注册驱动
    Class.forName("com.mysql.jsbc.Driver");
    //获得连接
    Connection conn = DriverManager.getConnection("jdbc:mysql:///test","root","root");
    //获得statement
    PreparedStatement sta = conn.prepareStatement("insert into user (id,name) values (?,?)");
    //设置占位符参数
    sta.setString(1,user,getId());
    sta.setString(2,user.getName());
    //插入操作
    int num = sta.executeUpdate();
    //释放资源
    sta.cloae();
    conn.close();
    

1.2、原始jdbc的额问题

  1. 数据库连接创建、释放频繁,影响系统性能
  2. sql语句在代码中为硬编码,不易维护
  3. 查询操作时,需要手动将结果集中的数据封装到实体中。插入时,需要手动设置占位符数据

1.3、解决方案

  1. 使用数据库连接池初始化连接资源
  2. 将sql语句抽取到xml文件中
  3. 使用反射、内省等底层奇数,自动将实体与表进行属性与字段的映射

Mybatis可实现

二、Mybatis开发步骤

  1. 添加Mybatis的坐标

     <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.22</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.5</version>
            </dependency>
    </dependencies>
    
  2. 创建user数据表

  3. 编写User实体类

    public class userEntity {
        private String id;
        private String username;
        private String password;
        private String hobby;
        private String email;
        //get...
        //set...
        
    }
    
  4. 编写映射文件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="userMapper">  <!--需要设置命名空间-->
        <!--删除-->
        <delete id="deleteUser" parameterType="com.zjj.mybatis01.Entity.userEntity">
            delete from t_user where id = #{id}
        </delete>
        <!--更新-->
        <update id="updateUser" parameterType="com.zjj.mybatis01.Entity.userEntity">
            update t_user set username = #{username} where id = #{id}
        </update>
        <!--添加-->
        <insert id="addUser" parameterType="com.zjj.mybatis01.Entity.userEntity">
            insert into t_user values (#{id},#{username},#{password},#{hobby},#{email})
        </insert>
        <!--查询-->
        <select id="selectAll" resultType="com.zjj.mybatis01.Entity.userEntity">   /*id自取;resultType为结果集封装对象*/
            select  * from t_user                       /*sql语句*/
        </select>
        
    </mapper>
    
  5. 编写核心文件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 default="environment1">
            <environment id="environment1">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/student?serverTimezone=UTC&amp;useSSL=false"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
        <!--加载映射文件-->
        <mappers>
            <mapper resource="com\zjj\mybatis01\Mapper\UserMapper.xml"/>
        </mapprs>
    </configuration>
    
  6. 测试(测试用例中部分代码重复,可抽取优化,这里不做处理)

    public class MybatisTest {
        /*删除*/
        @Test
        public void test3() throws IOException {
            //模拟实体对象
            userEntity userEntity = new userEntity();
            userEntity.setId("12");
            userEntity.setUsername("updateName");
    
            /*获得核心配置文件*/
            InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            /*获得session工厂*/
            SqlSessionFactory SessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            /*获得会话对象*/
            SqlSession sqlSession = SessionFactory.openSession();
            //执行操作
            sqlSession.delete("userMapper.deleteUser",userEntity);
            //提交事务
            sqlSession.commit();
            sqlSession.close();
        }
        /*更新*/
        @Test
        public void test2() throws IOException {
            //模拟实体对象
            userEntity userEntity = new userEntity();
            userEntity.setId("12");
            userEntity.setUsername("updateName");
    
            /*获得核心配置文件*/
            InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            /*获得session工厂*/
            SqlSessionFactory SessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            /*获得会话对象*/
            SqlSession sqlSession = SessionFactory.openSession();
            //执行操作
            sqlSession.update("userMapper.updateUser",userEntity);
            //提交事务
            sqlSession.commit();
            sqlSession.close();
        }
        /*添加*/
        @Test
        public void test1() throws IOException {
            //模拟实体对象
            userEntity userEntity = new userEntity();
            userEntity.setId("88");
            userEntity.setUsername("yyyy");
            userEntity.setPassword("123456");
            userEntity.setHobby("none");
            userEntity.setEmail("none");
    
            /*获得核心配置文件*/
            InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            /*获得session工厂*/
            SqlSessionFactory SessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            /*获得会话对象*/
            SqlSession sqlSession = SessionFactory.openSession();
            //执行操作
            sqlSession.insert("userMapper.addUser",userEntity);
            //提交事务
            sqlSession.commit();
            sqlSession.close();
        }
        /*查询*/
        @Test
        public void test0() throws IOException {
            /*获得核心配置文件*/
            InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            /*获得session工厂*/
            SqlSessionFactory SessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            /*获得会话对象*/
            SqlSession sqlSession = SessionFactory.openSession();
            //执行操作
            List<userEntity> userlist = sqlSession.selectList("userMapper.selectAll");
            System.out.println(userlist);
            sqlSession.close();
        }
    }
    
    

三、映射文件(UserMapper.xml)

3.1、根标签(mapper)

<mapper namespace=""></mapper>

映射文件的根标签为,标签属性“namespace”为命名空间,与下文语句的id一起组成查询标识

3.2、操作标签

  • 操作变迁共有四种:select、update、delete、insert
  • "id"为语句标识,与上面的命名空间组成查询标识;
  • 变迁中间为具体的操作sql语句
  1. <select id="selectAll" resultType="com.zjj.mybatis01.Entity.userEntity">
    	select  * from t_user
    </select>
    

    "resultType"为查询结果对应的实体类型

  2.     <insert id="addUser" parameterType="com.zjj.mybatis01.Entity.userEntity">
            insert into t_user values (#{id},#{username},#{password},#{hobby},#{email})
        </insert>
    

    "parameterType"为需要传入参数的实体类全限定名

    占位符的参数使用#{}来标识,打括号内为实体的"属性",与数据库表一一对应

  3.     <!--更新-->
        <update id="updateUser" parameterType="com.zjj.mybatis01.Entity.userEntity">
            update t_user set username = #{username} where id = #{id}
        </update>
    

    与增类似

  4.     <!--删除-->
        <delete id="deleteUser" parameterType="com.zjj.mybatis01.Entity.userEntity">
            delete from t_user where id = #{id}
        </delete>
    

    与增、改类似。如果根据某一个参数删除(如id),可以将parameterType中的全限定名改为java.lang.Integer等,此类型{}内可以为如何值

3.3、动态SQL

  1. if标签

    *使用if条件判断来确定传入的对象属性是否为空,如果为空则不以此为条件,否则将其拼接至sql语句;以此动态设置sql语句

    *where标签代表使用条件判断

    *场景:当根据传入实体的属性值(不确定哪些属性具有值)来动态查询

    <!--映射文件-->
    <select id="findByConditions" parameterType="userEntity" resultType="userEntity">
            select  * from t_user
            <where>
                <if test="id!=null">
                    and id=#{id}
                </if>
                <if test="username!=null">
                    and username=#{username}
                </if>
                <if test="password!=null">
                    and password=#{password}
                </if>
                <if test="hobby!=null">
                    and hobby=#{hobby}
                </if>
                <if test="email!=null">
                    and email=#{email}
                </if>
            </where>
        </select>
    

    测试:

    //测试
    @Test
        public void test01() throws IOException {
            userEntity user = new userEntity();
            user.setUsername("test1");
            user.setEmail("none");
    
            InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig2.xml");
            SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = build.openSession(true);
            userMapper mapper = sqlSession.getMapper(userMapper.class);
            //将根据user对象的属性值来确定sql语句,此例中即为:select  * from t_user where username = 'test1' and email = 'none'
            List<userEntity> userList = mapper.findByConditions(user);   
            System.out.println(userList);
    
        }
    
  2. foreach 标签

    场景:当根据同台个数的属性值来查询时(where id in (1,2,3,4)

    <!--foreach使用-->
        <select id="findByIds" resultType="userEntity" parameterType="list">
            select * from t_user
            <where>
                <foreach collection="list" open="id in (" close=")" item="id" separator=",">
                    #{id}
                </foreach>
            </where>
        </select>
    

    *collection :传入的集合/数组

    *open:where 关键词之后开始时不变的部分

    *close : where关键词之后结束时不变的部分

    *item:变量,代表list中每一个值

    *separator:分隔符

    测试

    @Test
        public void test02() throws IOException {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(3);
            list.add(5);
    
            InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig2.xml");
            SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = build.openSession(true);
            userMapper mapper = sqlSession.getMapper(userMapper.class);
            List<userEntity> userList = mapper.findByIds(list);
            System.out.println(userList);
        }
    
  3. sql语句片段抽取

    *使用sql标签设置sql语句片段,并设置id;在后面可直接使用include标签应用即可

    	<!--sql片段抽取-->
        <sql id="selectUser">select  * from t_user</sql>
    
        <!--if判断-->
        <select id="findByConditions" parameterType="userEntity" resultType="userEntity">
            <include refid="selectUser"></include>
    	</select>		
    

四、Mybatis核心配置文件(SqlMapConfig.xml)

4.1、基础

  • 根标签:

    <configuration></configuration>   
    
  • 内部标签

    • properties 属性

          <!--properties: 加载外部配置properties文件;内部调用使用${}-->
          <properties resource="jdbc.properties"></properties>
      
    • setting 设置

    • typeAliases 类型别名

          <!--typeAliases: 配置别名-->
          <typeAliases>
              <!--type为全限定名,alias为别名;通过该配置可以在映射文件中简写-->
              <typeAlias type="com.zjj.mybatis01.Entity.userEntity" alias="userEntity"/>  
          </typeAliases>
      
      <!--映射文件中   UserMapper.xml-->
          <!--查询-->
          <select id="selectAll" resultType="userEntity">   /*resultType只需要写别名即可*/
              select  * from t_user                      
          </select>
      

      在Mybatis中,一默认为String、int等数据类取别名,可直接使用

    • typeHandlers 类型处理器

    • objectFactory 对象工厂

    • plugins 插件

    • environments 环境

      • environment 环境变量
        • transactionManager 事务管理器
          • 事务管理器有两种类型(type 属性)
            1. JDBC :直接使用JDBC的提交和回滚设置,依赖于数据源的连接来管理事务
            2. MANAGED
        • dataSouce 数据源
          • 数据源有三种类型 (type 属性)
            1. UNPOOLED:该数据源的实现只是每次请求时打开或关闭连接
            2. POOLED:使用数据源方式
            3. JNDI
      <!--environments -->
      <environments default="environment1">
              <environment id="environment1">
                  <transactionManager type="JDBC"></transactionManager>
                  <dataSource type="POOLED">
                      <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                      <property name="url" value="jdbc:mysql://localhost:3306/student?serverTimezone=UTC&amp;useSSL=false"/>
                      <property name="username" value="root"/>
                      <property name="password" value="root"/>
                  </dataSource>
              </environment>
          </environments>
      
    • databaseIdProvider 数据库厂商标识

    • mappers 映射器

      <!--mappers :加载映射文件-->
      <mappers>
          <mapper resource="com\zjj\mybatis01\Mapper\UserMapper.xml"/> <!--相对路径来加载意映射文件-->
      </mappers>
      

4.2、深入

  1. typeHandlers标签

    该标签可以重写或自定义类型处理器

    实现步骤:

    1. 定义转换类型继承类BaseTypeHandler

    2. 覆盖4个为实现的方法,其中setNonNullParameter为将java数据类型转换为数据库数据类型;getNullableResult为将数据库数据类型转换为Java数据类型

      public class typeHandler extends BaseTypeHandler<Date> {
          //将java数据类型转换为数据库数据类型
          @Override
          public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
              long time = parameter.getTime();
              ps.setLong(i,time);
          }
          //将数据库类型转换为java数据类型
          @Override
          public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
              long aLong = rs.getLong(columnName);
              Date date = new Date(aLong);
              System.out.println("----------------"+columnName+"----------------");
              return date;
          }
          //将数据库类型转换为java数据类型
          @Override
          public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
              long aLong = rs.getLong(columnIndex);
              Date date = new Date(aLong);
              System.out.println("----------------"+columnIndex+"----------------");
              return date;
          }
          //将数据库类型转换为java数据类型
          @Override
          public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
              long aLong = cs.getLong(columnIndex);
              Date date = new Date(aLong);
              System.out.println("----------------"+columnIndex+"----------------");
              return date;
          }
      }
      
    3. 在mybatis核心配置文件中进行注册

      可使用resultMap代替resultType,好处在于resultMap可以使数据库字段名称与实体类属性名称不一致

      <mapper namespace="com.zjj.mybatis03.Usermapper">
       <!--   <resultMap id="resMao" type="userEntity">
              <id column="id" property="id"/>
              <result column="username" property="username"/>
              <result column="password" property="password"/>
              <result column="hobby" property="hobby"/>
              <result column="email" property="email"/>
              <result column="date" property="lodate"/>
          </resultMap>-->
          <!--可使用resultMap代替resultType,好处在于resultMap可以使数据库字段名称与实体类属性名称不一致-->
          <insert id="insertUser" parameterType="userEntity">
              insert into t_user values (#{id},#{username},#{password},#{hobby},#{email},#{date})
          </insert>
          <select id="selectUserById" parameterType="int"  resultType="userEntity">
              select  * from t_user where id = #{id}
          </select>
      </mapper>
      
    4. 测试转换是否正常

      public class typeHandlerTest {
      //测试查
          @Test
          public void test02() throws IOException {
              InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig3.xml");
              SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
              SqlSession sqlSession = build.openSession();
              Usermapper mapper = sqlSession.getMapper(Usermapper.class);
              userEntity userEntity = mapper.selectUserById(8);
              System.out.println(userEntity.getDate());
          }
          /**输出:
      ==>  Preparing: select * from t_user where id = ? 
      ==> Parameters: 8(Integer)
      <==    Columns: id, username, password, hobby, email, date
      <==        Row: 8, wangwu, 123456, yy, 121@, 1611994843687
      ----------------date----------------
      <==      Total: 1
      Sat Jan 30 16:20:43 CST 2021
         */
      
      //测试增
          @Test
          public void test01() throws IOException {
              userEntity userEntity = new userEntity();
              userEntity.setId("12");
              userEntity.setUsername("wangwu");
              userEntity.setPassword("123456");
              userEntity.setHobby("yy");
              userEntity.setEmail("121@");
              userEntity.setDate(new Date());
      
              InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig3.xml");
              SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
              SqlSession sqlSession = build.openSession(true);
              Usermapper mapper = sqlSession.getMapper(Usermapper.class);
              mapper.insertUser(userEntity);
          }
      }
      /**输出:
      ==>  Preparing: insert into t_user values (?,?,?,?,?,?) 
      ==> Parameters: 13(String), wangwu(String), 123456(String), yy(String), 121@(String), 1612000600318(Long)
      <==    Updates: 1
      */
      
  2. plugins标签

    plugins标签可以使用第三方插件来对功能进行扩展

    开发步骤(以分页为例):

    1. 导入通用PageHelper的坐标

      		<dependency>
                  <groupId>com.github.pagehelper</groupId>
                  <artifactId>pagehelper</artifactId>
                  <version>5.1.2</version>
              </dependency>
              <dependency>
                  <groupId>com.github.jsqlparser</groupId>
                  <artifactId>jsqlparser</artifactId>
                  <version>1.0</version>
              </dependency>
      
    2. 在mybatis核心配置文件中配置PageHelper插件

          <plugins>
              <plugin interceptor="com.github.pagehelper.PageInterceptor">
                  <!--<property name="dialect" value="mysql"/>-->
              </plugin>
          </plugins>
      

      注意,不同的pagehelper版本实现的接口不一样,所以配置不一样,具体如下:

      • 4.0.0以前配置为:com.github.pagehelper.PageHelper;以后为:com.github.pagehelper.PageInterceptor
      • 4.0.0以前需要写方言(“dialect”)识别数据库;4.0.0以后自动识别不需要写方言,写了反而报错
    3. 测试

      @Test
          public void test03() throws IOException {
              InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig3.xml");
              SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
              SqlSession sqlSession = build.openSession();
              Usermapper mapper = sqlSession.getMapper(Usermapper.class);
      
              //配置相关参数信息;当前页+每页数据个数
              PageHelper.startPage(1,3);
      
              List<userEntity> userEntities = mapper.selectAll();
              System.out.println("----------");
              for (userEntity u : userEntities){
                  System.out.println(u);
              }
      
              //获取pageBean中的相关信息
              PageInfo<userEntity> pageInfo = new PageInfo<>(userEntities);
              System.out.println("当前页:" + pageInfo.getPageNum());
              System.out.println("下一页:" + pageInfo.getNextPage());
              System.out.println("上一页:" + pageInfo.getPageNum());
              System.out.println("总页数:" + pageInfo.getPages());
              System.out.println("总条数:" + pageInfo.getTotal());
              System.out.println("是否为第一页:" + pageInfo.isIsFirstPage());
              System.out.println("是否为最后页:" + pageInfo.isIsLastPage());
      
              sqlSession.close();
          }
      

五、Mybatis相关API

5.1、SqlSession工厂构建器(SqlSessionFactoryBuilder)

具有方法:builder(Stream s)

/*配置文件路径*/
String resource = "SqlMapConfig.xml";
/*获得核心配置文件,可有多种方式加载*/
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
/*获得session工厂构造器*/
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
/*获得工厂*/
SqlSessionFactory factory = builder.build(resourceAsStream);

5.2、SqlSession对象构建器(SqlSessionFactory)

具有方法:

  • openSession() :默认开启事务,但不会自动提交,需要手动提交
  • openSession(boolean autoCommit) :传入参数为true,则自动提交
/*获得会话对象*/
SqlSession sqlSession = factory.openSession();

5.3、sqlSession对象


List<Object> objects = sqlSession.selectList(String Statement,Object o);  //查询多个
Object o = sqlSession.selectOne(String Statement,Object o);   //查询一个
int update = sqlSession.update(String Statement,Object o);    //更新
int insert = sqlSession.insert(String Statement,Object o);    //添加
int delete = sqlSession.delete(String Statement,Object o);    //删除
 sqlSession.commit();    //事务提交
sqlSession.close();    //关闭绘画

六、Mybatis的Dao实现

6.1、传统方法

即通过new 对象的方式手动实现

6.2、代理开发方式

Mybatis通过mapper接口的定义创建动态代理对象

规范:

  1. Mapper.xml文件中的namespace与mapper接口的全限定名必须一致
  2. Mapper接口方法名称和Mapper.xml文件中定义的每个statement的id相同
  3. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
  4. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的resultType的类型相同

实例:

mapper接口:

//mapper接口
public interface userDao {
	//查询
    public List<userEntity> selectAll();
    //添加
    public void addUser(userEntity u);
}

mapper.xml映射文件

<!--mapper.xml-->
<mapper namespace="com.zjj.mybatis01.Dao.userDao">
    <select id="selectAll" resultType="userEntity">
        select  * from t_user
    </select>
    <insert id="addUser" parameterType="userEntity">
        insert into t_user values (#{id},#{username},#{password},#{hobby},#{email})
    </insert>
</mapper>

测试

@Test
    public void test01() throws IOException {
        userEntity user = new userEntity();
        user.setId("100");
        user.setUsername("test1");
        user.setPassword("123456");
        user.setHobby("none");
        user.setEmail("none");

        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = build.openSession(true);
        //获取映射
        userDao mapper = sqlSession.getMapper(userDao.class);

        //查
        List<userEntity> userList = mapper.selectAll();
        System.out.println(userList);
        //增
        mapper.addUser(user);

    }

七、Mybatis多表查询

7.1、一对一查询

  1. 设置一对一的数据库(这里为订单order对用户user的关系。订单中的orders.userid对于用户中的t_user.id)

  2. 创建订单实体orderEntity

    //主要包含了order表中的字段,以及一个user包含用户信息 
    private String id;
    private String num;
    private userEntity user;
    
  3. 创建OrderMapper接口

    public interface OrderMapper {
        public List<orderEntity> selectOrder();
    }
    
  4. 配置映射文件

        <resultMap id="resOrder" type="orderEntity">
            <id column="id" property="id"/>       <!--查询获得的表中订单信息字段-->
            <result column="oerdernum" property="num"/>
            <result column="userid" property="user.id"/>
            <result column="username" property="user.username"/>   <!--查询获得的表中用户信息字段-->
            <result column="password" property="user.password"/>
            <result column="hobby" property="user.hobby"/>
            <result column="email" property="user.email"/>
            <result column="date" property="user.date"/>
        </resultMap>
        
        <select id="selectOrder" resultMap="resOrder">   <!--resultMap对应上面的resultMapId-->
            select *,o.id oid from t_user u, orders o where o.userid = u.id
        </select>
    

    使用resultMap配置来封装查询的数据;column为数据库中字段名称,property为实体类中属性名称

  5. 测试

7.2、一对多查询

  1. 设置一对多的数据库(这里为用户user对订单order的关系。用户中的t_user.id对于订单中的orders.userid,一个用户可存在多个订单)

  2. 创建用户实体userAndOrder

     private String id;
        private String username;
        private String password;
        private String hobby;
        private String email;
        private Date date;
    //用于存放用户订单信息
        private List<orderEntity> orderList;
    
  3. 创建OrderMapper接口

    public List<userAndOrderEntity> selectUsreAndOrder();
    
  4. 配置映射文件

        <resultMap id="userAndOrder" type="userAndOrder">
            <id column="userid" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
            <result column="hobby" property="hobby"/>
            <result column="email" property="email"/>
            <result column="date" property="date"/>
            <!--设置集合封装;property为userAndOrder中集合的名称,ofType为集合的类型-->
            <collection property="orderList" ofType="orderEntity">
                <!--封装order数据-->
                <id column="oid" property="id"/>
                <result column="oerdernum" property="num"/>
            </collection>
        </resultMap>
    
        <select id="selectUsreAndOrder" resultMap="userAndOrder">
            select *,o.id oid from t_user u, orders o where  u.id = o.userid
        </select>
    
  5. 测试

总结:在本例中,一对一与一对多的查询结果一致,但是封装的方式不同。订单对于商品为一对一,所以order实体中只需要保存订单信息和用户信息即可,用户信息使用一个user对象来保存;而用户对于订单为一对多,所以一个user实体中除了保存用户信息,还需要保存多个订单信息,所以使用集合保存订单信息。以此,有这两个差别之后,在映射文件中的配置(resultMap)也会不同,具体可见上面配置。

7.3、多对多查询

开发思想于一对多基本一致

八、注解开发

8.1、常用注解

  1. @Insert:实现增
  2. @Update:实现更新
  3. @Delete:实现删除
  4. @Select:实现查询
  5. @Result:实现结果集封装
  6. @Results:可以与@Result一起使用,封装多多个结果
  7. @One:实现一对一结果集封装
  8. @Many:实现一对多结果集封装

8.2、基本CRUD开发步骤

  1. 为mapper接口中的方法添加注释(参数为value:即xml映射配置文件中的sql语句)

    public interface userMapper {
        /*查询所有*/
        @Select("select * from t_user")
        public List<userEntity> selectAll();
    
        /*查询单个*/
        @Select("select * from t_user where id = #{id}")
        public  userEntity selectById(int id);
    
        /*新增*/
        @Insert("insert into t_user values (#{id},#{username},#{password},#{hobby},#{email})")
        public void addUser(userEntity u);
    
        /*更新*/
        @Update("update t_user set hobby = #{hobby} where id = #{id}")
        public void updateUser(userEntity u);
    
        /*删除*/
        @Delete("delete from t_user where id=#{int}")
        public void deleteUserById(int id);
    
    
  2. 扫描mapper接口所在的包,以获取相关注释

        <mappers>
            <!--扫描接口所在的包-->
            <package name="com.zjj.mybatis01.Mapper"/>
        </mappers>
    
  3. 测试

    public class Mybatis {
    
        private userMapper mapper;
    
        @Before
        public void Before() throws IOException {
            InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig3.xml");
            SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = build.openSession(true);
            mapper = sqlSession.getMapper(userMapper.class);
        }
    
        /*删除*/
        @Test
        public void test05(){
            mapper.deleteUserById(11);
        }
    
        /*更新*/
        @Test
        public void test04(){
            userEntity user = new userEntity();
            user.setId("15");
            user.setHobby("updateHobby");
            mapper.updateUser(user);
        }
    
        /*新增*/
        @Test
        public void test03(){
            userEntity user = new userEntity();
            user.setId("15");
            user.setUsername("laoliu");
            user.setPassword("123789");
            user.setHobby("dodo");
            user.setEmail("7899@123");
            mapper.addUser(user);
        }
    
        /*查询单个有*/
        @Test
        public void test02(){
            userEntity userEntity = mapper.selectById(5);
                System.out.println(userEntity);
        }
        
        /*查询所有*/
        @Test
        public void test01(){
            List<userEntity> userEntities = mapper.selectAll();
            for (userEntity u : userEntities){
                System.out.println(u);
            }
        }
    }
    

8.3、复杂映射注解(代替《resultMap》标签)

  • @Result :代替标签和标签;其中属性有:
    • column:数据库列名
    • property:实体属性名
    • one:需要使用的@One注解(@Result(one=@One)())
    • many:需要使用到的@Many注解(@Result(many=@Many)())
  • @Results:代替标签;其中可以使用单个@Result注解,也可以使用@Result集合。@Results({@Result(), @Result()})或@Results(@Result())
  • @One(一对一):代替标签,是多表查询的关键在注解中用来指定子查询返回单一对象;其属性有:
    • select:用来指定多表查询的sqlmapper
  • @Many(多对多):代替标签,是多对多表查询的关键,在注解中用来指定返回对象集合

8.4、一对一多表查询

一个订单对一个用户

order实体属性

    private String id;
    private String num;
    private userEntity user;

user实体属性

    private String id;
    private String username;
    private String password;
    private String hobby;
    private String email;

方法一:

    /*一对一查询*/
    @Select("select *,o.id oid from orders o, t_user u where o.userid = u.id") //多表夺标查询语句
    @Results({
            @Result(column = "oid",property = "id"),               //order实体属性封装3
            @Result(column = "oerdernum",property = "num"),
            @Result(column = "userid",property = "user.id"),         //user实体属性封装
            @Result(column = "username",property = "user.username"),
            @Result(column = "password",property = "user.password"),
            @Result(column = "hobby",property = "user.hobby"),
            @Result(column = "email",property = "user.email")
    })
    public List<orderEntity> selectOrders();

方法二:

    /*一对一查询*/
    @Select("select * from orders")      //查询一个单表orders
    @Results({
            @Result(column = "id",property = "id"),     //order实体属性封装
            @Result(column = "oerdernum",property = "num"),
            @Result(                                         //封装oerder实体中的user实体
                    property = "user",                       //order实体中user实体的对象名称
                    column = "userid",                       //查询得到orders表中外键的值useid,用来查询user表
                    javaType = userEntity.class,             //查询结果类类
                    //使用参数为查询user表方法所在的全限定名;方法查询语句为:select * from t_user where id = #{id}
                    one = @One(select = "com.zjj.mybatis01.Mapper.userMapper.selectById")    
            )
    })
    public List<orderEntity> selectOrders();
//查询user表方法
/*查询单个*/
    @Select("select * from t_user where id = #{id}")
    public  userEntity selectById(int id);

8.5、一对多表查询

一个用户有多个订单,先查绚user表,再根据user的id查询order表中的数据

用户实体

    private String id;
    private String username;
    private String password;
    private String hobby;
    private String email;
    private List<orderEntity> orderlist;

order实体

    private String id;
    private String oerdernum;

Mapper接口方法

    /*一对多表查询*/
    @Select("select * from t_user")
    @Results({
            @Result(id = true,column = "id", property = "id"),   //user实体属性
            @Result(column = "username", property = "username"),
            @Result(column = "password", property = "password"),
            @Result(column = "hobby", property = "hobby"),
            @Result(column = "email", property = "email"),
            @Result(                                         //List集合
                    column = "id",                           //待查询条件字段
                    property = "orderlist",					//集合名称
                    javaType = List.class,
                    many = @Many(select = "com.zjj.mybatis01.Mapper.orderMapper.selectOrderById")
            )
    })
    public List<userEntity> selectUserAndOrder();

selectOrderById方法

    @Select("select * from orders where userid = #{uid}")
    public List<orderEntity> selectOrderById(int uid);

测试

    /*一对多表查询*/
    @Test
    public void test02(){
        List<userEntity> userEntities = mapper2.selectUserAndOrder();
        for (userEntity u : userEntities) {
            System.out.println(u);
        }
    }

8.6、多对多表查询

于一对多查询操作步骤类似,区别在于:

多对多查询在 many = @Many(select = “com.zjj.mybatis01.Mapper.orderMapper.selectOrderById”)中的selectOrderById方法中的sql语句不同

    @Select("select * from table1 t1,order where t1.userid = #{uid} and t1.orderid = order.id ")
    public List<orderEntity> selectOrderById(int uid);

三表关系为:user表、t1为中间表(包含字段:id、userid、orderid)、order表通过中间表联系起来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值