Mybatis学习日志二

Mybatis学习日志二

学习目标

  • 能够掌握mybatis中的接口的CRUD
  • 能够掌握mybatis中的dao实现类方式的CRUD
  • 了解mybatis主配置文件的标签的使用

1 mybatis中的接口的CRUD

通过代理接口来实现CRUD操作

1.1 dao层接口

/**
 * 用户持久层接口
 */
public interface IUserDao {

    /**
     * 查询所有
     * @return
     */
    List<User> findAll();

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

    /**
     * 更新用户
     * @param user
     */
    void updateUser(User user);

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

    /**
     * 查询用户
     * @param userId 输入查询用户的ID
     * @return 返回查询对象
     */
    User findById(Integer userId);

    /**
     * 模糊查询用户
     * @param uName 根据用户名模糊查询
     * @return 模糊查询结果集
     */
    List<User> findByName(String uName);

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

1.2 关于映射文件配置中的问题

namespace 确定在哪个dao接口

id 是指的哪个方法

resultType 表示我们要将结果集封装到哪里去

parameterType 指的是我们我们方法中传入的参数类型

KeyProperty 指的是实体类中的属性

KeyColumn 指的是数据库中的列名

order 是决定此语句的执行顺序

注意事项:

  1. values中的参数需用#{}定义,并且在实体类中,有系统生成的get、set方法,#{?} ?必须是实体类中成员变量名称。
  2. 在id方法里有且只有一个形参,该形参如果是基本类型以及其包装类例如int、Integer…那么Sql语句中的#{?} ?任意字符即可。
 /**
	* IUserDao.xml
	* dao接口的映射配置文件
	*/
<mapper namespace="dao.IUserDao">
    <!-- 查询所有 -->
    <select id="findAll" resultType="domain.User">
        select * from user;
    </select>

    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="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>
    
    <!-- 更新用户 -->
    <update id="updateUser" parameterType="domain.User">
        update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id};
    </update>

    <!-- 删除用户 -->
    <delete id="deleteUser" parameterType="Integer">
        delete from user where id=#{userId};
    </delete>

    <!-- 查询用户 -->
    <select id="findById" parameterType="Integer" resultType="domain.User">
        select * from user where id=#{uid}
    </select>

    <!-- 模糊查询 -->
    <select id="findByName" resultType="domain.User" parameterType="String">
        select * from user where username like #{uName};<!-- 使用这种方法模糊查询,那么传入的查询条件必须左右自带一个% -->
        <!-- select * from user where username like '%${value}%'; value 是固定的,不可以为其他名字 -->
    </select>

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

1.3 测试代码及结果

初始化与事务提交并释放资源代码单独实现代码如下:

private InputStream in;
private SqlSession session;
private IUserDao userDao;

/**
 * 初始化
 * @throws IOException
 */
@Before//用于在测试方法之前执行
public void init() throws IOException {
    //1.获取配置文件
    in = Resources.getResourceAsStream("SqlMapConfig.xml");
    //2.获取SqlSessionFactory
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    //3.获取SqlSession对象
    session = factory.openSession();
    //4.获取代理对象
    userDao = session.getMapper(IUserDao.class);
}

/**
 * 事务提交并释放资源
 * @throws IOException
 */
@After//用于在测试方法之后执行
public void destroy() throws IOException {
    //1.提交事务
    session.commit();
    //2.释放资源
    session.close();
    in.close();
}

查询所有操作

/**
 * 测试查询所有操作
 *
 * @throws IOException
 */
@Test
public void testFindALL() {
    //1.执行查询所有方法
    List<User> users = userDao.findAll();
    //2.遍历结果集
    for (User user : users) {
        System.out.println(user);
    }
}

R_All

保存用户

@Test
public void testSave() {
    //1.创建用户
    User user = new User();
    user.setUsername("牛牛");
    user.setAddress("成都");
    user.setBirthday(new Date());
    user.setSex("男");
    System.out.println("保存前ID值:" + user.getId());
    //2.执行保存用户方法
    userDao.saveUser(user);
    System.out.println("保存后ID值:" + user.getId());
}

C_1

C_2

更新操作

@Test
public void testUpdate() {
    //1.确定用户
    User user = new User();
    //2.确定修改用户的id
    user.setId(50);
    user.setUsername("mybatis update user");
    user.setAddress("成都");
    user.setBirthday(new Date());
    user.setSex("女");
    //3.执行修改用户方法
    userDao.updateUser(user);
}

U

删除用户

@Test
public void testDelete() {
    //1.执行删除用户方法
    userDao.deleteUser(48);
}

通过ID查询用户

@Test
public void testFindById() {
    //1.执行查询用户方法
    User user = userDao.findById(50);
    System.out.println(user);
}

R_ID

通过用户名模糊查询

@Test
public void testFindByName() {
    //1.执行模糊查询用户方法
    List<User> users = userDao.findByName("%王%");
    for (User user : users) {
        System.out.println(user);
    }
}

R_NAME

查询总用户数

@Test
public void testFindTotal() {
    //1.执行查询总用户数方法
    int count = userDao.findTotal();
    System.out.println("总共用户数目为:" + count);
}

R

2 mybatis中的参数及返回值深入

2.1 参数深入–实体类的包装

OGNL表达式–Object Graphic Navigation Language

​ 对象 图 导航 语言

它是通过对象的取值方法来获取数据。在写法上把get省略了。

geg:我们获取用户的名称

  • ​ 类中的写法: user.getUserName();
  • ​ OGNL表达式:user.username

mybatis中为什么能直接写username,而不用user.呢?

答:因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名,而是直接写属性名。

实际开发中常常将多个实体类组成一个查询对象进行查询

/**
 * 根据queryVo中的条件查询用户
 * @param vo
 * @return
 */
List<User> findUserByVo(QueryVo vo);
public class QueryVo {
    private User user;
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
}
<!-- 根据QueryVo的条件查询用户 -->
<select id="findUserByVo" resultType="domain.User" parameterType="domain.QueryVo">
    select * from user where username like #{user.username};
</select>

这里的parameterType属性中传入QueryVo对象,那么#{}中填的值是用OGNL表达式,所以user表示QueryVo中的成员变量,用user.username表示User对象中的username。

2.2 返回值的深入–结果类型的封装

当实体类中的属性名称与数据库中列名不同时,查询操作将无法返回至实体类中。(注:Windows系统下mysql列名不分大小写)

解决方法:

  • 修改数据库中的列名与之实体类中的属性名一致。
  • 定义sql语句时起别名例如:(执行效率提高,后续维护成本高)
select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;
  • 映射文件xml中配置 查询结果的列名和实体类的属性名的对应关系。(执行效率低,后续维护效率高)

    • 定义一个结果映射
    <!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
    <resultMap id="userMap" type="domain.User">
        <!-- 主键字段对应 -->
        <id property="userId" column="id"></id>
        <!-- 非主键字段对应 -->
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
    </resultMap>
    
    • 此时其他配置中的resultType必须修改成resultMap="userMap"才能起作用。(resultMap中的值是配置结果集的id)
    <!-- 查询所有 -->
    <select id="findAll" resultMap="userMap">
        select * from user;
    </select>
    

resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的类名一致方可映射成功。

如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系,resultMap实质上还需要将查询结果映射到pojo对象中。

resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。

3 mybatis中的dao实现类方式的CRUD

  • mybatis 支持开发人员手写dao实现类。
  • 实际开发中,通常不写出dao的实现类。

查询所有

@Override
public List<User> findAll() {
    //1.根据Factory获取SqlSession对象
    SqlSession session = factory.openSession();
    //2.调用SqlSession中的方法,实现查询列表
    List<User> users = session.selectList("dao.IUserDao.findAll");//参数就是能获取到配置信息的key----配置文件中的namespace.方法名
    //3.释放资源
    session.close();
    return users;
}

保存用户

@Override
public void saveUser(User user) {
    //1.根据Factory获取SqlSession对象
    SqlSession session = factory.openSession();
    //2.调用方法实现保存
    session.insert("dao.IUserDao.saveUser",user);
    //3.提交事务
    session.commit();
    //4.释放资源
    session.close();
}

session.insert(String statement , Object parameter);

  • statement – 表示哪个配置来支持
  • parameter – 这个配置需要的参数是哪个

更新用户

@Override
public void updateUser(User user) {
    //1.根据Factory获取SqlSession对象
    SqlSession session = factory.openSession();
    //2.调用方法实现更新
    session.update("dao.IUserDao.updateUser",user);
    //3.提交事务
    session.commit();
    //4.释放资源
    session.close();
}

删除用户

@Override
public void deleteUser(Integer userId) {
    //1.根据Factory获取SqlSession对象
    SqlSession session = factory.openSession();
    //2.调用方法实现删除用户
   session.delete("dao.IUserDao.deleteUser",userId);
    //3.提交事务
    session.commit();
    //4.释放资源
    session.close();
}

通过ID查询一个用户

@Override
public User findById(Integer userId) {
    //1.根据Factory获取SqlSession对象
    SqlSession session = factory.openSession();
    //2.调用SqlSession中的方法,实现查询用户
    User user = session.selectOne("dao.IUserDao.findById",userId);
    //3.释放资源
    session.close();
    return user;
}

查询总用户数

@Override
public int findTotal() {
    //1.根据Factory获取SqlSession对象
    SqlSession session = factory.openSession();
    //2.调用SqlSession中的方法,实现查询用户
    int count = session.selectOne("dao.IUserDao.findTotal");
    //3.释放资源
    session.close();
    return count;
}

PreparedStatement对象它的执行方法

  • execute:它能执行CRUD中的任意一种语句。它的返回值是一个boolean类型,表示是否有结果集。
  • executeUpdate:它只能执行CUD语句,查询语句无法执行。它的返回值是影响数据库记录的行数。
  • executeQuery:它只能执行SELECT语句,无法执行CUD。执行结果封装的结果集为ResultSet对象。

4 mybatis主配置文件的标签的使用

properties标签:

可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置文件信息。在外部配置数据库信息便于维护。

  • resource属性:用于指定配置文件的位置,是按照类路径的写法,且必须存在于类路径下。
  • url属性:要求Url的写法来写地址
    • URL:Uniform Resource Locator 统一资源定位符。唯一标识一个资源的位置。
      • 它的写法:http://localhost:8080/mybatisserver/demo
    • URI:Uniform Resource Identifier 统一资源标识符。唯一定位一个资源。
      • 它的写法:file:///E:\2021\个人仓库\mybatis\cn_kq_day2\day2_01CRUD\src\main\resources

typeAliases标签:

配置别名,它只能配置domain中类的别名

  • typeAlias 用于配置别名。
    • ​ type属性指定的是实体类全限定类名。
    • ​ alias属性指定别名。
<typeAliases>
    <typeAlias type="domain.User" alias="user"></typeAlias>
</typeAliases>

注:当指定了别名就不再区分大小写

  • package 用于指定要配置别名的包
    • 当指定之后,该包下的实体类都会注册别名。类名就是别名,不再区分大小写。
<typeAliases>
    <package name="domain"/>
</typeAliases>

mappers标签:

  • mapper 指定映射文件的位置

    • resource dao接口映射文件的位置
    • class dao接口的位置(@注解时使用)
    <mappers>	
    	<mapper resource="dao/IUserDao.xml"/>
    </mappers>
    
  • package 指定dao接口所在的包

    • name dao接口包位置所在
      • 注:当指定了之后就不需要再写mapper以及resource或者class了。
    <mappers>
    	<package name="dao"/>
    </mappers>
    

注:两者不能同时写。

一键转到→Mybatis学习日志三

源自黑马+自我总结,如有错误之处望指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值