美文网首页
第二天:mybatis基本使用

第二天:mybatis基本使用

作者: 阿杰_96c5 | 来源:发表于2020-03-28 22:24 被阅读0次

    第二天:mybatis基本使用

    mybatis框架 学习计划

    共四天
    第一天:mybatis入门
    mybatis的概述
    mybatis的环境搭建
    mybatis入门案例
    自定义mybatis框架(主要的目的是为了让大家了解mybatis中执行细节)
    第二天:mybatis基本使用
    mybatis的单表crud操作
    mybatis的参数和返回值
    mybatis的dao编写
    mybatis配置的细节
    几个标签的使用
    第三天:mybatis的深入和多表
    mybatis的连接池
    mybatis的事务控制及设计的方法
    mybatis的多表查询
    一对多(多对一)
    多对多
    第四天:mybatis的缓存和注解开发
    mybatis中的加载时机(查询的时机)
    mybatis中的一级缓存和二级缓存
    mybatis的注解开发
    单表CRUD
    多表查询

    使用要求:
    1、持久层接口和持久层接口的映射配置必须在相同的包下
    2、持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
    3、SQL 语句的配置标签<select>,<insert>,<delete>,<update>的 id 属性必须和持久层接口的
    方法名相同。

    2.1 基于代理 Dao 实现 CRUD 操作

    2.1.1根据 ID 查询

    在持久层接口中添加 findById 方法

    /**
     * 根据Id查询用户
     */
    User findById(Integer id);
    
    <!-- 根据Id查询用户-->
    <select id="findById" parameterType="java.lang.Integer" resultType="org.example.domain.User">
    select * from  user where id = #{id}
    </select>
    在用户的映射配置文件中配置细节:
    resultType 属性:
        用于指定结果集的类型。
    parameterType 属性:
        用于指定传入参数的类型。
    sql 语句中使用#{}字符:
        它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
        具体的数据是由#{}里面的内容决定的。
    #{}中内容的写法:
        由于数据类型是基本类型,所以此处可以随意写。
    
    

    在测试类添加测试

    public class MybatisTest {
    
        private  InputStream in;
        private  SqlSession sqlSession;
        private  UserDao userDao;
    
        @Before  // test方法执行之前执行
        public void init() throws IOException {
                //1.读取配置文件
                 in = Resources.getResourceAsStream("SqlMapConfig.xml");
                //2.创建 SqlSessionFactory 的构建者对象
                SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    
                //3.使用构建者创建工厂对象 SqlSessionFactory
                SqlSessionFactory factory = builder.build(in);
    
                //4.使用 SqlSessionFactory 生产 SqlSession 对象
                sqlSession = factory.openSession();
    
                //5.使用 SqlSession 创建 dao 接口的代理对象
                userDao = sqlSession.getMapper(UserDao.class);
    
        }
    
        @After // test方法执行之后执行
        public void destroy() throws IOException {
            //提交事务
            sqlSession.commit();
            //7.释放资源
            sqlSession.close();
            in.close();
        }
    
        
        @Test
        public void testFindAll() throws IOException {
            //6.使用代理对象执行查询所有方法
            List<User> users = userDao.findAll();
            for(User user : users) {
                System.out.println(user);
            }
        }
        
         /**
         * 测试根据id查询用户
         */
        @Test
        public void testDFindById(){
            User user = userDao.findById(49);
            System.out.println(user);
        }
    }
    

    2.1.2 保存操作

    在持久层接口中添加新增方法

    /**
     * 保存用户
     * @param user
     * @return 影响数据库记录的行数
     */
    int saveUser(User user);
    

    在用户的映射配置文件中配置

    <!-- 保存用户-->
    <insert id="saveUser">
        新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相
    当于我们要在新增后将自动增长 auto_increment 的值返回。
    <!-- 配置插入操作后,获取出入数据的id-->
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        INSERT
        INTO
            user
            (username, address, sex, birthday)
        VALUES
            (#{username}, #{address}, #{sex}, #{birthday});
    </insert>
    细节:
    parameterType 属性:
        代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。
    sql 语句中使用#{}字符:
        它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
        具体的数据是由#{}里面的内容决定的。
    #{}中内容的写法:
        由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。
        它用的是 ognl 表达式。
    ognl 表达式:
        它是 apache 提供的一种表达式语言,全称是:
    Object Graphic Navigation Language
        对象图导航语言
        它是按照一定的语法格式来获取数据的。
        语法格式就是使用 #{对象.对象}的方式
            #{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.而直接写 username。
    

    添加测试类中的测试方法

    @Test
    public void testSave() throws IOException {
        User user = new User();
        user.setUsername("mybatis saveuser2");
        user.setAddress("天涯海角");
        user.setSex("男");
        user.setBirthday(new Date());
        System.out.println("保存之前:" + user);
        // 执行保存
        userDao.saveUser(user);
        System.out.println("保存之后:" + user);
    }
        打开 Mysql 数据库发现并没有添加任何记录,原因是什么?
        这一点和 jdbc 是一样的,我们在实现增删改时一定要去控制事务的提交,那么在 mybatis 中如何控制事务提交呢?
        可以使用:session.commit();来实现事务提交。加入事务提交后的代码如下:
        @After // test方法执行之后执行
        public void destroy() throws IOException {
            //提交事务
            sqlSession.commit();
            //7.释放资源
            sqlSession.close();
            in.close();
        }
    
    

    2.1.3 用户更新

    在持久层接口中添加更新方法

    /**
     * 更新用户
     * @param user
     * @return 影响数据库记录的行数
     */
    int updateUser(User user);
    

    在用户的映射配置文件中配置

    <!--更新用户-->
    <update id="updateUser" parameterType="org.example.domain.User">
        UPDATE user
        SET username = #{username},
            address = #{address},
            sex = #{sex},
            birthday = #{birthday}
        WHERE id = #{id}
    

    加入更新的测试方法

    /**
     * 更新测试
     */
    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(49);
        user.setUsername("mybatis 49");
        user.setAddress("天涯海角");
        user.setSex("男");
        user.setBirthday(new Date());
        // 执行保存
        userDao.updateUser(user);
    }
    

    2.1.4 用户删除

    在持久层接口中添加删除方法

    /**
     * 根据id删除用户
     * @param id
     * @return 影响数据库记录的行数
     */
    int deleteUser(Integer id);
    

    在用户的映射配置文件中配置

    <!-- 根据id删除用户-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id = #{id}
    </delete>
    

    加入删除的测试方法

    /**
     * 测试删除
     */
    @Test
    public void testDelete(){
        userDao.deleteUser(50);
    }
    

    2.1.5 用户模糊查询

    在持久层接口中添加模糊查询方法

    /**
     * 根据名称模糊查询用户信息
     */
    List<User> findByName(String username);
    

    在用户的映射配置文件中配置

    <!-- 根据名称模糊查询用户信息 -->
    <select id="findByName" parameterType="java.lang.String"  resultType="org.example.domain.User">
        select * from user where username like concat('%',#{username},'%')
    </select>
    

    加入模糊查询的测试方法

    /**
     * 测试迷糊查询
     */
    @Test
    public void testFindByName(){
        List<User> list = userDao.findByName("小二");
        for (User user: list) {
            System.out.println(user);
        }
    }
    

    2.1.6 查询使用聚合函数

    在持久层接口中添加模糊查询方法

    /**
     * 查询总用户数
     * @return
     */
    int findTotal();
    

    在用户的映射配置文件中配置

    <!--查询总的用户数-->
    <select id="findTotal" resultType="int">
        select count(*) from user
    </select>
    

    加入聚合查询的测试方法

    /**
     *  测试查询总的用户数
     */
    @Test
    public void testFindTotal(){
        int total = userDao.findTotal();
        System.out.println("总用户数: " + total);
    }
    

    2.1.7#{}${}的区别

    #{}表示一个占位符号
    通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
    **{}表示拼接 sql 串** 通过{}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, {}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,{}括号中只能是 value。

    2.2 mybatis的参数和返回值

    2.2.1 parameterType 配置参数

    ​ 我们在上一章节中已经介绍了 SQL 语句传参,使用标签的 parameterType 属性来设定。该属性的取值可以是基本类型,引用类型(例如:String 类型),还可以是实体类类型(POJO 类)。同时也可以使用实体类的包装类,本章节将介绍如何使用实体类的包装类作为参数传递。

    ​ 基 本 类 型 和 String 我 们 可 以 直 接 写 类 型 名 称 , 也 可 以 使 用 包 名 . 类 名 的 方 式 , 例 如 :java.lang.String。

    ​ 实体类类型,目前我们只能使用全限定类名。
    究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。在今天课程的最后一个章节中将讲解如何注册实体类
    的别名。

    别名 映射的类型
    _byte byte
    _long long
    _short short
    _int int
    _integer int
    _double double
    _float float
    _boolean boolean
    string String
    byte Byte
    long Long
    short Short
    int Integer
    integer Integer
    double Double
    float Float
    boolean Boolean
    date Date
    decimal BigDecimal
    bigdecimal BigDecimal
    object Object
    map Map
    hashmap HashMap
    list List
    arraylist ArrayList
    collection Collection
    iterator Iterator

    2.2.2 传递 pojo 包装对象

    ​ 开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
    Pojo 类中包含 pojo。
    需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。

    1. 编写 QueryVo
    /**
     * 查询条件对象
     */
    public class QueryVo implements Serializable {
    
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    }
    
    1. 编写持久层接口
    /**
     * 根据QueryVo中的条件查询用户
     * @param vo
     * @return
     */
    List<User> findByVo(QueryVo vo); 
    
    1. 持久层接口的映射文件

      <!--根据QueryVo中的条件查询用户-->
      <select id="findByVo" parameterType="org.example.domain.QueryVo" resultType="org.example.domain.User">
          select * 
          from user 
          where username like concat('%',#{user.username},'%')
      </select>
      
      1. 测试包装类作为参数
      /**
       * 测试根据QueryVo中的条件查询用户
       */
      @Test
      public void testFindByVo(){
          QueryVo vo = new QueryVo();
          User user = new User();
          user.setUsername("王");
          vo.setUser(user);
          List<User> list = userDao.findByVo(vo);
          for (User u: list) {
              System.out.println(u);
          }
      }
      

    2.2.3 resultType 配置结果类型

    ​ resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。
    我们在前面的 CRUD 案例中已经对此属性进行过应用了。
    需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须
    使用全限定类名。例如:我们的实体类此时必须是全限定类名(今天最后一个章节会讲解如何配置实体类的别名)
    同时,当是实体类名称是,还有一个要求,实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。

    2.2.3.1 基本类型示例

    1. Dao 接口
    // 查询总记录条数
    int findTotal();
    
    1. 映射配置

    2. <!-- 查询总记录条数 -->
      <select id="findTotal" resultType="int">
        select count(*) from user;
      </select>
      

    2.2.3.2 实体类类型示例

    1. Dao 接口
    /**
     * 查询所有用户操作
     * @return
     */
    List<User> findAll();
    
    1. 映射配置
    <!-- 配置查询所有操作 -->
    <select id="findAll" resultType="org.example.domain.User">
        select * from user
    </select>
    

    2.2.4 resultMap 结果类型

    resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
    select 标签中使用 resultMap 属性指定引用即可。同时 resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括 pojolist 实现一对一查询和一对多查询。

    1.定义 resultMap

    <!-- 建立 User 实体和数据库表的对应关系
        type 属性:指定实体类的全限定类名
        id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
    -->
    <resultMap type="org.example.domain.User" id="userMap">
        <id column="id" property="userId"/>
        <result column="username" property="userName"/>
        <result column="sex" property="userSex"/>
        <result column="address" property="userAddress"/>
        <result column="birthday" property="userBirthday"/>
    </resultMap>
    id 标签:用于指定主键字段
    result 标签:用于指定非主键字段
    column 属性:用于指定数据库列名
    property 属性:用于指定实体类属性名称 
    
    1. 映射配置

      <select id="findAll" resultMap="userMap">
       select * from user
      </select>    
      

    2.3 SqlMapConfig.xml配置文件

    2.3.1 配置内容

    -properties(属性)
        --property
    -settings(全局配置参数)
        --setting
    -typeAliases(类型别名)
        --typeAliase
        --package
    -typeHandlers(类型处理器)
    -objectFactory(对象工厂)
    -plugins(插件)
    -environments(环境集合属性对象)
        --environment(环境子属性对象)
            ---transactionManager(事务管理)
            ---dataSource(数据源)
    -mappers(映射器)
        --mapper
        --package
    

    2.3.2 properties(属性)

    ​ 在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。

    第一种

    <dataSource type="POOLED">
        <!-- 配置连接数据库的4个基本信息-->
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/easy?useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </dataSource>
    

    第二种

    1. classpath 下定义 db.properties文件

      properties 标签设置 resource="jdbcConfig.properties" 可以直接使用

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/eesy
    jdbc.username=root
    jdbc.password=1234
    
    <properties resource="jdbcConfig.properties">
    </properties>
    
    <environments default="mysql">
            <!--配置mysql的环境-->
            <environment id="mysql">
                <!-- 配置事务类型-->
                <transactionManager type="JDBC"/>
                <!-- 配置数据源(连接池)-->
                <dataSource type="POOLED">
                    <!-- 配置连接数据库的4个基本信息-->
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
    
    
    1. properties标签配置
    <!-- 配置连接数据库的信息
    resource 属性:用于指定 properties 配置文件的位置,要求配置文件必须在类路径下
    resource="jdbcConfig.properties"
    url 属性:
        URL: Uniform Resource Locator 统一资源定位符
        http://localhost:8080/mystroe/CategoryServlet
    
    URI
        URI:Uniform Resource Identifier 统一资源标识符
        /mystroe/CategoryServlet
        它是可以在 web 应用中唯一定位一个资源的路径
    -->
    
    <properties url=file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">
    </properties>
    
    1. 此时我们的 dataSource 标签就变成了引用上面的配置

      <dataSource type="POOLED">
          <property name="driver" value="${jdbc.driver}"/>
          <property name="url" value="${jdbc.url}"/>
          <property name="username" value="${jdbc.username}"/>
          <property name="password" value="${jdbc.password}"/>
      </dataSource>
      

    2.3.3 mappers(映射器)

    1. <mapper resource=" " />
    使用相对于类路径的资源
    如:<mapper resource="com/itheima/dao/IUserDao.xml" />
    
    1. <mapper class=" " />
    使用 mapper 接口类路径
    如:<mapper class="com.itheima.dao.UserDao"/>
    注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
    
    1. <package name=""/>
    注册指定包下的所有 mapper 接口
    如:<package name="cn.itcast.mybatis.mapper"/>
    注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
    

    相关文章

      网友评论

          本文标题:第二天:mybatis基本使用

          本文链接:https://www.haomeiwen.com/subject/prjeuhtx.html