一、基于代理DAO实现CRUD操作

1.1 根据ID查询

1.1.1 持久层接口 IUserDao

    /**
     * 根据ID查用户
     * @param userId
     * @return
     */
    User findById(Integer userId);

1.1.2 映射配置文件 IUserDao.xml

  • resultType:用于指定结果集的类型
  • parameterType:用于指定传入参数的类型
  • sql语句中的#{}:代表占位符,相当于原先JDBC中的?,用于执行语句时替换实际的数据。

    • 数据类型为基本类型可随意填写
    <!-- 根据ID查用户-->
    <select id="findById" parameterType="int" resultType="com.ruki.domain.User">
        select * from user where id=#{id};
    </select>

1.2 保存操作

1.2.1 持久层接口 IUserDao

    /**
     * 保存用户
     * @param user
     */
    void saveUser(User user);

1.2.2 映射配置文件 IUserDao.xml

  • parameterType:代表参数的类型,因为要传入的是一个类的对象,所以类型就写类的全名称
  • #{}:参数占位符

    • 由于保存方法的参数是一个User对象,此处要写User对象中的属性名称,因此采用OGNL表达式。
    • OGNL表达式

      • 是APACHE提供的一种表达式语言
      • Object Graphic Navigation Language 对象图导航语言
      • 它是按照一定的语法格式来获取数据的
      • #{对象.对象}
      • #{user.username}它会先去找user对象,然后在user对象中找到username属性,并调用getUsername()方法把值取出来。但由于在parameterType属性上指定了实体类名称,所以可以省略user.,而直接写username
  • selectKey

    • keyProperty:实体类中主键的属性名
    • keyColumn:表中主键的属性名
    • resultType:结果类型
    • order:执行顺序
    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="com.ruki.domain.User">
        <!-- 配置保存时获取插入的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>

1.3 用户更新

1.3.1 持久层接口 IUserDao

    /**
     * 修改用户信息
     * @param user
     */
    void update(User user);

1.3.2 映射配置文件 IUserDao.xml

    <!-- 修改用户信息-->
    <update id="update" parameterType="com.ruki.domain.User">
        update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
    </update>

1.4 用户删除

1.4.1 持久层接口 IUserDao

    /**
     * 删除用户
     * @param userId
     */
    void deleteUser(Integer userId);

1.4.2 映射配置文件 IUserDao.xml

    <!-- 根据id删除用户
            参数类型:int INT INTEGER Integer都行-->
    <delete id="deleteUser" parameterType="integer">
        delete from user where id=#{id}
    </delete>

1.5 用户模糊查询

1.5.1 持久层接口 IUserDao

    /**
     * 根据名字模糊查询
     * @param name
     * @return
     */
    List<User> findByName(String name);

1.5.2 映射配置文件 IUserDao.xml

  • 模糊查询第一种配置方式

    • select * from USER where username like #{name}
    • 传入的参数需要自己带%,使用的是preparedStatement预编译,推荐使用
  • 模糊查询第二种配置方式

    • select * from user where username like '%${value}%'
    • 传入参数不用带%,使用的是字符串拼接,不推荐
    <!-- 根据用户名模糊查询 -->
    <select id="findByName" parameterType="String" resultType="com.ruki.domain.User">
        <!-- preparedStatement预处理了,推荐使用 -->
        <!--select * from USER where username like #{name} -->

        <!-- 字符串的拼接,不推荐 -->
        select * from user where username like '%${value}%'
    </select>

1.5.3 #{}与${}的区别

  • #{}表示一个占位符号

    • 通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和Jdbc类型转换,#{}可以有效防止sql注入。#{}可以接收简单类型或pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或其他名称
  • ${}表示拼接sql串

    • 通过${}可以将parameterType传入的内容拼接在sql中且不进行Jdbc转换,${}可以接收简单类型值或pojo属性值,如果patameterType传输单个简单类型值,${}括号中只能是value

1.6 查询使用聚合函数

1.6.1 持久层接口 IUserDao

    /**
     * 查询一行一列的结果,聚合函数
     * @return
     */
    int findTotalCount();

1.6.2 映射配置文件 IUserDao.xml

    <!-- 查询总记录数 -->
    <select id="findTotalCount" resultType="int">
        select count(id) from user
    </select>

1.7 测试

package com.ruki.test;

import com.ruki.dao.IUserDao;
import com.ruki.domain.QueryVo;
import com.ruki.domain.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 MybatisTest {
    private InputStream in;
    private SqlSession session;
    private IUserDao userDao;

    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(in);
        session = sessionFactory.openSession();
        userDao = session.getMapper(IUserDao.class);
    }

    @After
    public void destroy() throws IOException {
        session.commit();//提交事务
        session.close();
        in.close();

    }

    /**
     * 测试查询所有用户
     */
    @Test
    public void testFindAll() throws IOException {
        List<User> list = userDao.findAll();
        for(User user : list){
            System.out.println(user);
        }
    }

    /**
     * 测试保存用户
     */
    @Test
    public void testSaveUser(){
        User user = new User();
        user.setUsername("test02 last_insert_id");
        user.setAddress("浙江杭州市");
        user.setSex("男");
        user.setBirthday(new Date());
        System.out.println("保存前:" + user);
        userDao.saveUser(user);
        System.out.println("保存后:" + user);
    }

    /**
     * 测试更新用户信息
     */
    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(50);
        user.setUsername("test01 update");
        user.setSex("女");
        userDao.update(user);
    }

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

    /**
     * 根据ID查用户
     */
    @Test
    public void testFindById(){
        User user = userDao.findById(45);
        System.out.println(user);
    }

    /**
     * 测试根据用户名模糊查询
     */
    @Test
    public void testFindByName(){
//        List<User> users = userDao.findByName("%王%");
        List<User> users = userDao.findByName("王");
        for(User user : users){
            System.out.println(user);
        }
    }

    /**
     * 查询总记录数 - 聚合函数
     */
    @Test
    public void testGetTotalCount(){
        int totalCount = userDao.findTotalCount();
        System.out.println(totalCount);
    }
}

二、MyBatis参数的深入

2.1 patameterType配置参数

2.1.1 使用说明

  • sql语句传参,使用标签的parameterType属性来设定,该属性的取值可以是基本类型,引用类型(String),还可以是实体类类型(pojo),同时也可以使用实体类的包装类。

2.1.2 注意事项

  • 基本类型和String,可以直接写类型名称,也可以使用包名.类名的方式,如java.lang.String
  • 实体类类型,在不手动注册别名的情况下,只能使用全限定类名。
  • MyBatis在加载时已经把常用的数据类型注册了别名,而使用自己写的实体类没有注册,所以必须写全限定类名。

2.2 传递pojo包装对象

2.2.1 编写QueryVo

package com.ruki.domain;

public class QueryVo {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

2.2.2 编写持久层接口

    /**
     * 根据实体类的包装对象进行模糊查询
     * @param vo
     * @return
     */
    List<User> findByVo(QueryVo vo);

2.2.3 持久层接口的映射文件

    <!-- 根据实体类的包装对象进行模糊查询 -->
    <select id="findByVo" parameterType="com.ruki.domain.QueryVo" resultType="com.ruki.domain.User">
        select * from user where username like #{user.username};
    </select>

2.2.4 测试

    /**
     * 将查询条件包装成实体类的对象,
     * 并将其作为参数传入,
     * 使用OGNL表达式获得对象中的具体参数
     */
    @Test
    public void testFindUserByVo(){
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUsername("%王%");
        vo.setUser(user);

        List<User> users = userDao.findByVo(vo);
        for(User u : users){
            System.out.println(u);
        }
    }

三、MyBatis的输出结果封装

3.1 resultType配置结果类型

  • resultTypeparameterType一样,如果注册过别名可以直接使用别名,没有注册过,只能使用全限定类名。
  • 实体类中属性名称必须和查询语句汇总的列名保持一致,否则无法实现封装。

3.2 修改实体类属性名

  • 此时实体类属性名和表中字段名不一致

3.2.1 实体类

public class User implements Serializable { 
    private Integer userId; 
    private String userName; 
    private Date userBirthday; 
    private String userSex; 
    private String userAddress;
    //..getter and setter
}
  • 从查询结果可以发现,只有userName被封装了起来,其余都为null

    • 原因:mysql在window中不区分大小写,因此和表中字段名一致。

3.2.2 解决方式1:修改映射配置(起别名)

<!-- 配置查询所有操作 --> 
<select id="findAll" resultType="com.itheima.domain.User"> 
    select id as userId,username as userName,birthday as userBirthday, sex as userSex,address as userAddress from user 
</select>
  • 缺陷:若查询很多或属性很多,使用别名会很麻烦。

3.2. 解决方式2:resultMap

  • id标签:用于指定主键字段
  • result标签:用户指定非主键字段
  • colomn属性:用于指定数据库列名
  • property属性:用于指定实体类属性名称
<!-- 建立User实体和数据库表的对应关系
    type属性:指定实体类的全限定类名 
    id属性:给定一个唯一标识,是给查询select标签引用用的。 --> 
<resultMap type="com.itheima.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>
<!-- 配置查询所有操作 --> 
<select id="findAll" resultMap="userMap"> 
    select * from user 
</select>

四、SqlMapConfig.xml

4.1 配置内容

4.1.1 配置内容和顺序

  1. properties:属性

    1. property
  2. settings:全局配置参数

    1. setting
  3. typeAliases:类型别名

    1. typeAliase
    2. package
  4. typeHandlers:类型处理器
  5. objectFactory:对象工厂
  6. plugins:插件
  7. environments:环境集合属性对象

    1. environment:环境子属性对象

      1. transactionManager:事务管理
      2. dataSource:数据源
  8. mappers:映射器

    1. mapper
    2. package

4.2 properties(属性)

4.2.1 方式1

<properties>
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mybatis01"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</properties>

4.2.2 方式2

4.2.2.1 在classpath下定义db.properties

  • db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis01
jdbc.username=root
jdbc.password=root

4.2.2.2 properties标签配置

    <!-- 配置properties
        可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置文件信息
        resource属性:
            用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下
        url属性:
            按照url的写法来写地址
            URL:uniform resource locator 统一资源定位符。可以唯一标识一个资源的位置
                写法:
                    http://localhost:8080/mybatis/demo1Servlet
                    协议    主机     端口   URI

           URI:uniform resource identifier 统一资源标识符。在应用中可以唯一定位
     -->
    <!--<properties resource="jdbcConfig.properties"></properties>-->
    <properties url="file:///D:/IDEAworkspace/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties"></properties>

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

4.3 typeAliases(类型别名)

  • 自定义别名
  • typeAliases:用于配置别名

    • type属性:实体类全限定类名
    • alias属性:指定别名。<font color="red">不区分大小写</font>
    • package标签:指定要配置别名的包。<font color="red">别名就是类名</font>
    <typeAliases>
        <!-- typeAlias用于配置别名。
            type属性:
                指定的是实体类全限定类名。
            alias属性:
                指定别名。指定了别名就不再区分大小写
             -->
        <!-- 单个别名定义 -->
        <<typeAlias type="com.ruki.domain.User" alias="user"></typeAlias>
        
        <!-- 批量别名定义,扫描整个包下的类,别名为类名(不区分大小写) -->
        <!-- 用于指定要配置别名的包当指定之后,该包下的实体类都会注册别名
                并且类名就是别名,不再区分大小写-->
        <package name="com.ruki.domain"/>
    </typeAliases>

4.4 mappers(映射器)

4.4.1 <mapper resource="" />(基于xml配置文件)

  • 使用相对于类路径的资源

    <mapper resource="com/ruki/dao/IUserDao.xml" />

4.4.2 <mapper class="" />(基于注解)

  • 使用mapper或者说是dao接口类路径

    <mapper class="com.ruki.dao.IUserDao"/>

4.4.3 <package name="" />

  • 注册指定包下的所有mapper或者说是dao接口

        <mappers>
            <!-- package标签用于指定dao接口所在的包,当制定了之后就不需要再写mapper以及resource(xml配置文件形式)或者class(注解形式)了 -->
            <package name="com.ruki.dao"/>
        </mappers>
    • <font color="red">此种方法要求mapper或者说dao接口名称和mapper映射文件名称相同,且放在同一个目录中</font>
Last modification:September 15th, 2019 at 03:03 pm