MyBatis简单学习上

一、学习规划

7月22号,我的暑假正式开始了,接下来的时间将开始学习Java EE的部分了,每天大概花五六小时的时间学习吧,然后利用晚上的时间整理当天学习过的内容。(小声bb:9月还有四级考试,有点绝望)

二、什么是框架

框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。 简而言之,框架其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。

框架一般处在低层应用平台(如 J2EE)和高层业务逻辑之间的中间层。

分层开发下的常见框架:
  • 解决数据的持久化问题的框架

    MyBatis

    注:作为持久层的框架,还有一个封装程度更高的框架就是Hibernate,但这个框架因为各种原因,目前在国内的流行程度下降太多,现在公司开发也越来越少使用。目前使用Spring Data来实现数据持久化也是一种趋势。

  • 解决Web层问题的MVC框架

    Spring MVC

  • 解决技术整合问题的框架

    Spring

    目的:解决企业应用开发的复杂性

    功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

    范围:任何Java应用

    Spring是一个轻量级控制反转(IOC)和面向切面(AOP)的容器框架

三、MyBatis框架的认知

MyBatis框架概述:

mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。

采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

JDBC问题分析:

1、数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

2、Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java代码。

3、使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。

4、对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便。

四、搭建MyBatis开发环境

创建maven工程:
添加MyBatis3.4.5的坐标:

在pom.xml文件中添加MyBatis3.4.5的坐标,如下:

<packaging>jar</packaging>

<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>
编写User实体类:
/**
 * @author boy
 * @create 2020-07-22 11:18
 */
public class User implements Serializable {

    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
#### 	编写持久层接口UserDao:
/**
 * @author boy
 * @create 2020-07-22 11:20
 *
 * 用户的持久层接口
 */
public interface UserDao {

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

}
编写持久层接口的映射文件 UserDao.xml:

注:创建位置:必须和持久层接口在相同的包中。名称必须以持久层接口名称命名文件名,扩展名是.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="com.itheima.dao.UserDao">

    <!-- 配置查询所有 -->
    <select id="findAll" resultType="com.itheima.domain.User">
        select * from user
    </select>

</mapper>
编写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">

<!-- mybatis的主配置文件 -->
<configuration>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池) -->
            <dataSource type="POOLED">
                <!-- 配置连接数据库的4个基本信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
    <mappers>
        <mapper resource="com/itheima/dao/UserDao.xml"/>
    </mappers>
</configuration>
编写测试类:
package com.itheima.test;


import com.itheima.dao.UserDao;
import com.itheima.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author boy
 * @create 2020-07-22 14:44
 */
public class MybatisTest {

    /**
     * 入门案例
     * @param args
     */
    public static void main(String[] args) throws Exception {
        // 1. 读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2. 创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        // 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();
        in.close();
    }

}

补充(基于注解的MyBatis使用):

在持久层接口中添加注解:
/**
 * @author boy
 * @create 2020-07-22 11:20
 *
 * 用户的持久层接口
 */
public interface UserDao {

    /**
     * 查询所有操作
     * @return
     */
    @Select("select * from user")
    List<User> findAll();

}
修改SqlMapConfig.xml:
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件
    如果是用注解来配置的话,此处应该使用class属性指定被注解的dao全限定类名
-->
<mappers>
    <mapper class="com.itheima.dao.UserDao"/>
</mappers>
注意事项:

在使用基于注解的 Mybatis 配置时,请移除 xml 的映射配置(UserDao.xml)。

五、基于代理Dao实现CRUD操作

使用要求:

1、持久层接口和持久层接口的映射配置必须在相同的包下

2、持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名

3、SQL 语句的配置标签,,,的 id 属性必须和持久层接口的

方法名相同。

根据ID查询:

在持久层接口中添加findById方法:
/**
 * 根据id查询用户信息
 * @param userId
 * @return
 */
User findById(Integer userId);
在用户的映射配置文件中配置:
<!-- 根据id查询用户 -->
<select id="findById" parameterType="int" resultType="com.itheima.domain.User">
    select * from user where id = #{uid}
</select>

细节:
resultType 属性:
用于指定结果集的类型。
parameterType 属性:
用于指定传入参数的类型。
sql 语句中使用#{}字符:
它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。

在测试类中添加测试:
public class MybastisCRUDTest {

	private InputStream in ;

	private SqlSessionFactory factory;

	private SqlSession session;

	private UserDao userDao;


	@Test

	public void testFindOne() {

		//6.执行操作

		User user = userDao.findById(41);

		System.out.println(user);

	}
    

	@Before//在测试方法执行之前执行

	public void init() throws Exception {

		//1.读取配置文件

		in = Resources.getResourceAsStream("SqlMapConfig.xml");

		//2.创建构建者对象

		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

		//3.创建 SqlSession 工厂对象

		factory = builder.build(in);

		//4.创建 SqlSession 对象

		session = factory.openSession();

		//5.创建 Dao 的代理对象

		userDao = session.getMapper(UserDao.class);

	}
    
    @After//在测试方法执行完成之后执行
	public void destroy() throws Exception{
		session.commit();
		//7.释放资源
		session.close();
		in.close();
	} 
}

保存操作:

在持久层接口中添加新增方法:
/**
 * 保存用户
 * @param user
 */
void saveUser(User user);
在用户的映射配置文件中配置:
<!-- 保存用户--> 
<insert id="saveUser" parameterType="com.itheima.domain.User">
	insert into user(username,birthday,sex,address) 
    	values(#{username},#{birthday},#{sex},#{address})
</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(){
        User user = new User();
        user.setUsername("modify User property");
        user.setAddress("北京市顺义区");
        user.setSex("男");
        user.setBirthday(new Date());
        System.out.println("保存操作之前:"+user);
        //5.执行保存方法
        userDao.saveUser(user);
        System.out.println("保存操作之后:"+user);
    }
	打开 Mysql 数据库发现并没有添加任何记录,原因是什么?
	这一点和 jdbc 是一样的,我们在实现增删改时一定要去控制事务的提交,那么在 mybatis 中如何控制事务
提交呢?
	可以使用:session.commit();来实现事务提交。加入事务提交后的代码如下:
    @After//在测试方法执行完成之后执行
    public void destroy() throws Exception{
        session.commit();
        //7.释放资源
        session.close();
        in.close();
    }
问题扩展:新增用户id的返回值:

新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。

<!-- 保存用户 -->
<insert id="saveUser" parameterType="user">
    <!-- 配置插入操作后,获取插入数据的id -->
    <selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
        select last_insert_id();
    </selectKey>
    insert into user(username, address, sex, birthday) values(#{userName}, #{userAddress}, #{userSex}, #{userBirthday});
</insert>

用户更新:

在持久层接口中添加更新方法:
/**
 * 更新用户
 * @param user
 */
void updateUser(User user);
在用户的映射配置文件中配置:
<!-- 更新用户 --> 

<update id="updateUser" parameterType="com.itheima.domain.User">

    update user set username=#{username},birthday=#{birthday},sex=#{sex},

    address=#{address} where id=#{id}

</update>
加入更新的测试方法:
/**
 * 测试更新操作
 */
@Test
public void testUpdate() {
    User user = new User();
    user.setUserId(53);
    user.setUserName("mybatis saveuser");
    user.setUserAddress("广东省揭阳市");
    user.setUserSex("女");
    user.setUserBirthday(new Date());

    // 5. 执行保存方法
    userDao.updateUser(user);
}

用户删除:

在持久层接口中添加删除方法:
/**
 * 删除用户
 * @param id
 */
void deleteUser(Integer id);
在用户的映射配置文件中配置:
<!-- 删除用户 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
    delete from user where id = #{uid}
</delete>
加入删除的测试方法:
/**
 * 测试删除操作
 */
@Test
public void testDelete() {
    // 5. 执行删除方法
    userDao.deleteUser(56);
}

用户模糊查询:

在持久层接口中添加模糊查询方法:
/**
 * 根据名称模糊查询
 * @param username
 * @return
 */
List<User> findByName(String username);
在用户的映射配置文件中配置:
<!-- 根据名称模糊查询 -->
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
    select * from user where username like #{username}
    <!--select * from user where username like '%${value}%'-->
</select>
加入模糊查询的测试方法:
    /**
     * 测试模糊查询操作
     */
    @Test
    public void testFindByName() {
        // 5. 执行查询一个方法
        List<User> users = userDao.findByName("%王%");
//        List<User> users = userDao.findByName("王");
        for (User user : users) {
            System.out.println(user);
        }
    }

注:使用的#{userName}只是一个占位符,所以SQL语句显示为“ ?”。而注释掉的句子中,使用的是固定的${value}写法,不能写成其他名字,所以SQL语句显示为“ %王% ”。

#{}和${}的区别:

#{}表示一个占位符号

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

${}表示拼接sql串

通过 可 以 将 p a r a m e t e r T y p e 传 入 的 内 容 拼 接 在 s q l 中 且 不 进 行 j d b c 类 型 转 换 , {}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, parameterTypesqljdbc{}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。

查询使用聚合函数:

在持久层接口中添加查询总数方法:
/**
 * 查询总用户数
 * @return
 */
Integer findTotal();
在用户的映射配置文件中配置:
<!-- 获取用户的总记录数 -->
<select id="findTotal" resultType="int">
    select count(*) from user;
</select>
加入聚合查询的测试方法:
/**
 * 测试查询总记录条数
 */
@Test
public void testFindTotal() {
    // 5. 执行查询总记录数方法
    Integer total = userDao.findTotal();
    System.out.println(total);
}

六、MyBatis 与 JDBC 编程的 比较

  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

    解决:

    在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。

  2. Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。

    解决:

    将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。

  3. 向 sql 语句传参数麻烦,因为 sql 语句的 where 条件不一定,可能多也可能少,占位符需要和参数对应。

    解决:

    Mybatis 自动将 java 对象映射至 sql 语句,通过 statement 中的 parameterType 定义输入参数的类型。

  4. 对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo对象解析比较方便。

    解决:

    Mybatis 自动将 sql 执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的类型。

七、MyBatis的参数深入

parameterType 配置参数

使用说明:

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

注意事项:

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

实体类类型,目前我们只能使用全限定类名。

究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。

Alias(别名)Mapped Type(映射的类型)
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

这些都是支持的默认别名。我们也可以从源码角度来看它们分别都是如何定义出来的。可以参考 TypeAliasRegistery.class 的源码。

传递 Entity 包装对象:

编写QueryVo:
/**
 * @author boy
 * @create 2020-07-23 9:42
 */
public class QueryVo {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}
编写持久层接口:
/**
 * 根据queryVo中的条件查询用户
 * @param vo
 * @return
 */
List<User> findUserByVo(QueryVo vo);
持久层接口的映射文件:
<!-- 根据queryVo的条件查询用户 -->
<select id="findUserByVo" parameterType="com.itheima.domain.QueryVo" resultMap="userMap">
    select * from user where username like #{user.userName}
    <!--select * from user where username like '%${value}%'-->
</select>
测试包装类作为参数:
    /**
     * 测试使用QueryVo作为查询条件
     */
    @Test
    public void testFindUserByVo() {
        QueryVo vo = new QueryVo();
        User u= new User();
        u.setUserName("%王%");
        vo.setUser(u);
        // 5. 执行查询一个方法
        List<User> users = userDao.findUserByVo(vo);
//        List<User> users = userDao.findByName("王");
        for (User user : users) {
            System.out.println(user);
        }
    }

八、MyBatis的输出结果封装

resultType 配置结果类型

基本类型示例:

Dao接口:
/**
 * 查询总用户数
 * @return
 */
Integer findTotal();
映射配置:
<!-- 获取用户的总记录数 -->
<select id="findTotal" resultType="int">
    select count(id) from user;
</select>

实体类类型示例:

Dao接口:
/**
 * 查询所有
 * @return
 */
List<User> findAll();
映射配置:
<!-- 查询所有 -->
<select id="findAll" resultType="com.itheima.domain.User">
    select * from user;
</select>

特殊情况示例:

修改实体类:
/**
 * @author boy
 * @create 2020-07-22 19:30
 */
public class User implements Serializable {

    private Integer userId;
    private String userName;
    private String userAddress;
    private String userSex;
    private Date userBirthday;

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }

    public String getUserSex() {
        return userSex;
    }

    public void setUserSex(String userSex) {
        this.userSex = userSex;
    }

    public Date getUserBirthday() {
        return userBirthday;
    }

    public void setUserBirthday(Date userBirthday) {
        this.userBirthday = userBirthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userAddress='" + userAddress + '\'' +
                ", userSex='" + userSex + '\'' +
                ", userBirthday=" + userBirthday +
                '}';
    }
}
Dao接口:
/**
 * 查询所有
 * @return
 */
List<User> findAll();
映射配置:
<!-- 查询所有 -->
<select id="findAll" resultType="com.itheima.domain.User">
    <!--select id as userId, username as userName, address as userAddress, sex as userSex, birthday as userBirthday from user;-->
    select * from user;
</select>
测试查询结果:
@Test
public void testFindAll(){
    // 5. 执行查询所有方法
    List<User> users = userDao.findAll();
    for (User user : users) {
        System.out.println(user);
    }
}

此处:除userName外,其他都没有值。

原因:mysql 在 windows 系统中不区分大小写!

修改映射配置:
<!-- 查询所有 -->
<select id="findAll" resultType="com.itheima.domain.User">
    select id as userId, username as userName, address as userAddress, sex as userSex, birthday as userBirthday from user;
</select>

resultMap 结果类型

定义 resultMap:
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="userMap" type="user">
    <!-- 主键字段的对应 -->
    <id property="userId" column="id"></id>
    <!-- 非主键字段的对应 -->
    <result property="userName" column="username"></result>
    <result property="userAddress" column="address"></result>
    <result property="userSex" column="sex"></result>
    <result property="userBirthday" column="birthday"></result>
</resultMap>
映射配置:
<!-- 查询所有 -->
<select id="findAll" resultMap="userMap">
    select * from user;
</select>
测试结果:
@Test
public void testFindAll(){
    // 5. 执行查询所有方法
    List<User> users = userDao.findAll();
    for (User user : users) {
        System.out.println(user);
    }
}

九、MyBatis 传统 Dao 层开发[了解]

MyBatis 实现 Dao 的传统开发方式

持久层 Dao 接口:
package com.itheima.dao;

import com.itheima.domain.QueryVo;
import com.itheima.domain.User;

import java.util.List;

/**
 * 用户的持久层接口
 *
 * @author boy
 * @create 2020-07-22 19:37
 */
public interface UserDao {

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

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

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

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

    /**
     * 根据id查询用户信息
     * @param userId
     * @return
     */
    User findById(Integer userId);

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

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

    /**
     * 根据queryVo中的条件查询用户
     * @param vo
     * @return
     */
    List<User> findUserByVo(QueryVo vo);
}
持久层 Dao 实现类:
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

/**
 * @author boy
 * @create 2020-07-23 10:19
 */
public class UserDaoImpl implements UserDao {

    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }

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

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

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

    public void deleteUser(Integer id) {
        // 1. 根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        // 2. 调用方法实现保存
        session.update("com.itheima.dao.UserDao.deleteUser", id);
        // 3. 提交事务
        session.commit();
        // 4. 释放资源
        session.close();
    }

    public User findById(Integer userId) {
        // 1. 根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        // 2. 调用SqlSession中的方法,实现查询列表
        //      参数就是能获取配置信息的key
        User user = session.selectOne("com.itheima.dao.UserDao.findById", userId);
        // 3. 释放资源
        session.close();
        return user;
    }

    public List<User> findByName(String username) {
        // 1. 根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        // 2. 调用SqlSession中的方法,实现查询列表
        //      参数就是能获取配置信息的key
        List<User> users = session.selectList("com.itheima.dao.UserDao.findByName", username);
        // 3. 释放资源
        session.close();
        return users;
    }

    public Integer findTotal() {
        // 1. 根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        // 2. 调用SqlSession中的方法,实现查询列表
        //      参数就是能获取配置信息的key
        Integer count = session.selectOne("com.itheima.dao.UserDao.findTotal");
        // 3. 释放资源
        session.close();
        return count;
    }
}
持久层映射配置:
<?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="com.itheima.dao.UserDao">

    <!-- 查询所有 -->
    <select id="findAll" resultType="com.itheima.domain.User">
        select * from user;
    </select>

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

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

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

    <!-- 根据名称模糊查询 -->
    <select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
        select * from user where username like #{username}
        <!--select * from user where username like '%${value}%'-->
    </select>

    <!-- 获取用户的总记录数 -->
    <select id="findTotal" resultType="int">
        select count(id) from user;
    </select>
</mapper>
测试类:
package com.itheima.test;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.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.InputStream;
import java.util.Date;
import java.util.List;

/**
 * @author boy
 * @create 2020-07-22 19:40
 */
public class MybatisTest {

    private InputStream in;
    private UserDao userDao;

    @Before // 用于在测试方法执行之前执行
    public void init() throws Exception {
        // 1. 读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2. 获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3. 使用工厂对象,创建dao对象
        userDao = new UserDaoImpl(factory);
    }

    @After  // 用于在测试方法执行之后执行
    public void destroy() throws Exception {
        // 6. 释放资源
        in.close();
    }

    @Test
    public void testFindAll(){
        // 5. 执行查询所有方法
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 测试保存操作
     */
    @Test
    public void testSave() {
        User user = new User();
        user.setUsername("dao impl user");
        user.setAddress("广东省揭阳市");
        user.setSex("男");
        user.setBirthday(new Date());

        // 5. 执行保存方法
        userDao.saveUser(user);
        System.out.println(user);
    }

    /**
     * 测试更新操作
     */
    @Test
    public void testUpdate() {
        User user = new User();
        user.setId(53);
        user.setUsername("mybatis saveuser");
        user.setAddress("广东省揭阳市");
        user.setSex("男");
        user.setBirthday(new Date());

        // 5. 执行保存方法
        userDao.updateUser(user);
    }

    /**
     * 测试删除操作
     */
    @Test
    public void testDelete() {
        // 5. 执行删除方法
        userDao.deleteUser(55);
    }

    /**
     * 测试查询一个操作
     */
    @Test
    public void testFindOne() {
        // 5. 执行查询一个方法
        User user = userDao.findById(53);
        System.out.println(user);
    }

    /**
     * 测试模糊查询操作
     */
    @Test
    public void testFindByName() {
        // 5. 执行查询一个方法
        List<User> users = userDao.findByName("%王%");
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 测试查询总记录条数
     */
    @Test
    public void testFindTotal() {
        // 5. 执行查询总记录数方法
        Integer total = userDao.findTotal();
        System.out.println(total);
    }
}

十、SqlMapConfig.xml配置文件

配置内容

SqlMapConfig.xml 中配置的内容和顺序:

-properties(属性)

–property

-settings(全局配置参数)

​ --setting

-typeAliases(类型别名)

–typeAliase

–package

-typeHandlers(类型处理器)

-objectFactory(对象工厂)

-plugins(插件)

-environments(环境集合属性对象)

​ --environment(环境子属性对象)

​ —transactionManager(事务管理)

​ —dataSource(数据源)

-mappers(映射器)

–mapper

–package

properties(属性)

第一种:
<properties> 

    <property name=*"jdbc.driver"* value=*"com.mysql.jdbc.Driver"*/>

    <property name=*"jdbc.url"* value=*"jdbc:mysql://localhost:3306/eesy"*/>

    <property name=*"jdbc.username"* value=*"root"*/>

    <property name=*"jdbc.password"* value=*"1234"*/>

</properties>
第二种:

在 classpath 下定义 jdbc.properties 文件:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis
jdbc.username=root
jdbc.password=123456

properties 标签配置:

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

        URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。
-->
<properties url="file:///D:/IdeaProjects/JavaEE/Mybatis/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">
    <!--<property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>-->
</properties>

此时我们的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>

typeAliases(类型别名)

自定义别名:
<!-- 使用typeAliases配置别名,它智能配置domain中类的别名 -->
<typeAliases>
    <!-- typeAlias用于配置别名。
    type属性指定的是实体类全限定类名;
    alias属性指定别名,当指定了别名就再区分大小写 -->
    <!--<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
    
    <!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写 -->
    <package name="com.itheima.domain"></package>
</typeAliases>

mappers(映射器)

  • <mapper resource=" " />

使用相对于类路径的资源

如:<mapper resource=“com/itheima/dao/UserDao.xml” />

  • <mapper class=" "/>

使用 mapper 接口类路径

如:<mapper class=“com.itheima.dao.UserDao”/>

注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

  • <package name=" "/>

注册指定包下的所有 mapper 接口

如:<package name=“cn.itcast.mybatis.mapper”/>

可以唯一定位一个资源的。

<properties url="file:///D:/IdeaProjects/JavaEE/Mybatis/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">
    <!--<property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>-->
</properties>

此时我们的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>

typeAliases(类型别名)

自定义别名:
<!-- 使用typeAliases配置别名,它智能配置domain中类的别名 -->
<typeAliases>
    <!-- typeAlias用于配置别名。
    type属性指定的是实体类全限定类名;
    alias属性指定别名,当指定了别名就再区分大小写 -->
    <!--<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
    
    <!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写 -->
    <package name="com.itheima.domain"></package>
</typeAliases>

mappers(映射器)

  • ** <mapper resource=" "\ />**

使用相对于类路径的资源

如:<mapper resource=“com/itheima/dao/UserDao.xml” />

  • <mapper class=" " />

使用 mapper 接口类路径

如:<mapper class=“com.itheima.dao.UserDao”/>

注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

  • <package name=" "/>

注册指定包下的所有 mapper 接口

如:<package name=“cn.itcast.mybatis.mapper”/>

注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值