Java小白修炼手册--第五阶段--MyBatis框架( day01)

目录

MyBatis

MyBatis框架简介

什么是MyBatis

MyBatis体系结构

MyBatis框架的作用

MyBatis配置文件

框架API简介

SqlSessionFactoryBuilder

SqlSessionFactory

SqlSession

MyBatis基本应用

搭建MyBatis技术环境

获取SqISession对象

CRUD(增,删,改,查)操作

利用SqISession实现CRUD操作

利用MyBatis实现分页查询

返回Map类型查询结果

使用Mapper映射器

ResultMap映射定义

项目实例:

创建数据库 并连 接数据库

@PropertySource("classpath:jdbc.properties") 读取配置文件值

@Bean  配置DataSource对象,并将该对象交给框架处理:

Tests测试类

单元测试注解有:  @BeforeClass ,@Before,@Test,@After,@AfterClass

单元测试方法的声明规范:

  < 1 >必须添加@Test注解;

  < 2 >必须使用public权限;

 < 3 >必须使用void作为返回值类型;

  < 4 >必须保持空参数列表(不允许有参数)

创建数据表

插入数据

定义抽象方法

配置SQL语句

配置SqlSessionFactoryBean的对象

MyBatis框架能够自动获取数据库连接,并完成数据访问

UserMapperTests测试类

获取自动编号的ID值

@Options(useGeneratedKeys=true, keyProperty="id")

删除用户数据

修改用户数据

@Before:初始化方法对于每一一个测试方法都要执行一次

@After:释放资源对于每一个测试方法都要执行一次

测试用例执行顺序为

@Before > @Test > @After

统计数量

查询用户信息


MyBatis

MyBatis框架简介


什么是MyBatis

  • MyBatis最早源自Apache基金会的一个开源项目iBatis,2010年这个项目由Apache software foundation迁移到了google code ,并且改名为MyBatis ;
  • MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。
  • MyBatis封装了几乎所有的JDBC代码和参数的手工设置以及结果集的检索;
  • MyBatis使用简单的XML或注解做配置和定义映射关系将Java的POJOs ( Plain Old Java Objects )映射成数据库中的记录。

MyBatis体系结构

MyBatis体系结构主要由以下几个关键部分
1 )加载配置
配置有两种形式,一种是XML配置文件,另一种是Java代码的注解。MyBatis将SQL 的配置信息加载成为一个个的MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置) , 并将其存储在内存中
2 ) SQL解析
-当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基 本数据类型)Mybatis会根据SQL的ID找到对应的MappedStatement ,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
3 ) SQL执行
将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
4 )结果映射
将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。

MyBatis框架的作用

MyBatis框架的主要作用是简化持久层开发。当使用MyBatis处理数据的增删改查时,只需要定义访问数据的抽象方法,并配置该抽象方法对应的SQL语句即可!

持久层:解决项目中数据持久化处理的组件。

数据持久化:将数据永久的保存下来,即将数据存储在硬盘等可以永久保存数据的存储介质中,如果要将数据保存在这些存储介质中,数据需要以文件的形式存在,通常,可以将数据存到文本文档、XML文档、数据库,通常,在没有明确的说明的情况下,讨论数据持久化指的就是使用数据库存取数据。

内存(RAM,具体表现通常是内存条):是CPU与其它硬件交换数据的“桥梁”,正在执行的程序和数据都在内存中,一旦断电则数据全部丢失。

MyBatis配置文件

<properties>
    <!-- java version -->
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <!-- dependency version -->
    <mybatis.version>3.5.4</mybatis.version>
    <mybatis.spring.version>2.0.5</mybatis.spring.version>
    <spring.version>5.2.7.RELEASE</spring.version>
    <mysql.version>8.0.12</mysql.version>
    <druid.version>1.1.23</druid.version>
    <junit.version>4.13</junit.version>
</properties>

<dependencies>
    <!-- MyBatis:mybatis -->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>${mybatis.version}</version>
    </dependency>
    <!-- MyBatis整合Spring:mybatis-spring -->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>${mybatis.spring.version}</version>
    </dependency>
    <!-- Spring:spring-context -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- Spring JDBC:spring-jdbc -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- MySQL:mysql-connector-java -->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>
    <!-- 连接池:druid -->
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
    </dependency>
    <!-- 单元测试:junit -->
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>


框架API简介
 

在使用MyBatis框架时,主要涉及以下几个API


SqlSessionFactoryBuilder


该对象负责根据MyBatis配置文件SqlMapConfig.xml构建SqlSessionFactory实例


SqlSessionFactory


每一个MyBatis的应用程序都以-个SqISessionFactory对象为核心。该对象负责创建SqlSession对象实例


SqlSession


-该对象包含了所有执行SQL操作的方法,用于执行已映射的SQL语句
 

MyBatis基本应用


搭建MyBatis技术环境

在使用MyBatis之前,需要将MyBatis框架添加到工程项目中, 主要步骤如下

  • 为工程添加MyBatis开发包和数据库驱动包;
  • 在src下添加MyBatis配置文件SqIMapConfig.xml
  • 修改SqIMapConfig.xml,指定数据库连接参数
  • 利用MyBatis API编程,获取Sq|Session实例

获取SqISession对象

String conf = "SqlMapConfig.xml";
Reader reader = Resources.getResourceAsReader(conf);
//创建SessionFactory对象
SqISessionFactoryBuildersfb =
new SqlSessionFactoryBuilder();
SqlSessionFactorysf = sfb.build(reader);
//创建Session
SqlSession session = sf.openSession();

CRUD(增,删,改,查)操作

crud是指在做计算处理时的增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。crud主要被用在描述软件系统中数据库或者持久层的基本操作功能。


利用SqISession实现CRUD操作

当获取SqlSession对象后,就可以利用它对数据表执行增删改查操作了,使用步骤如下

  • 根据数据表编写实体类( Java POJO )
  • 编写SqlMap.xml映射文件,定义SQL操作和映射信息
  • 获取SqlSession对象,执行增删改查操作
  • 提交事务( DML操作)
  • 释放Sq|Session对象资源
     
//添加操作的SqlMap.xmI定义
<insert id=" addDept" parameterType=" org.tarena.entity.Dept'">
insert into DEPT (DEPTNO,DNAME,LOC)
values (#{deptno},#{dname},#{loc})
</insert>
//添加操作的Java代码
SqlSession session = sf.openSession();
//调用addDept操作
session.insert("addDept" ,dept);
session.commit();
Session.close();


利用MyBatis实现分页查询


返回Map类型查询结果

SqlMap.xml映射定义


<select id= "findDept”parameter Type= "int'
    resultType= "java.util.HashMap">
    select DEPTNO,DNAME from DEPT where DEPTNO=#{no}
</select>

SqlSession的用法 


SqlSession session = sf.openSession(); 
Map map = (Map)session.selectOne("findDept" ,10);
System.out.println(map.get("DEPTNO");
System.out.println(map.get("DNAME'");


使用Mapper映射器

Mapper映射器是开发者创建绑定映射语句的接口,映射器接口的实例可以从SqlSession中获得。


SqlSession session = sqlSessionFactory.openSession();
    try {
        DeptMapper mapper = session.getMapper(DeptMapper.class); 
         //do work
    } finally {
        session.close();
    }

DeptMapper接定义如下
Mapper接口中的方法名要和SqIMap.xml中的SQL的id保持一致。 


public interface DeptMapper {
    public List<Dept> findAl();
    public Dept findByld(int id);
    public void addDept(Dept dept);
    public void updateDept(Dept dept);
    public void deleteByld(int id);
}


ResultMap映射定义

在SqlMap.xml定义<select>操作时,如果查询结果字段名和Java POJO属性不一致时, 需要使用<resultMap>元素显式指定映射关系。例如

<select id= "findAll1" resultMap="deptMap">
    select DEPTNO,DNAME, LOC from DEPT
</select>
    <resultMap id= "deptMap" type= "org.tarena.entity.Dept">
    <result property="no" column= "DEPTNO"/>
    <result property= "name" column="DNAME"/>
    <result property= "Ioc" column="LOC "/>
</resultMap>

项目实例:

创建数据库 并连 接数据库

首先,登录MySQL控制台,创建tedu_ums数据库:

CREATE DATABASE tedu_ums;

然后,在项目中,在src/main/resources下创建jdbc.properties文件,用于配置连接数据库的相关信息:

spring.datasource.url=jdbc:mysql://localhost:3306/tedu_ums?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.initialSize=2
spring.datasource.maxActive=10

@PropertySource("classpath:jdbc.properties") 读取配置文件值

接下来,在项目的src/main/java下创建cn.tedu.mybatis包,并在这个包下创建SpringConfig类,在该类中声明属性以读取以上配置值:

package cn.tedu.mybatis;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;

@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
	
	@Value("${spring.datasource.url}")
	private String url;
	@Value("${spring.datasource.driver-class-name}")
	private String driverClassName;
	@Value("${spring.datasource.username}")
	private String username;
	@Value("${spring.datasource.password}")
	private String password;
	@Value("${spring.datasource.initialSize}")
	private Integer initialSize;
	@Value("${spring.datasource.maxActive}")
	private Integer maxActive;
	
}

@Bean  配置DataSource对象,并将该对象交给框架处理:

添加方法,将以上读取到的信息用于配置DataSource对象,并将该对象交给框架处理:

注意:使用DataSource时,导包必须导javax.sql包中的接口。

@Bean
public DataSource dataSource() {
    // 当前项目添加依赖时
    // 数据库连接池使用的是druid
    // 所以,此处创建DruidDataSource的对象
    // 如果以后改用其它数据库连接池
    // 则创建其它数据库连接池中的对象即可
    DruidDataSource ds = new DruidDataSource();
    ds.setUrl(url);
    ds.setDriverClassName(driverClassName);
    ds.setUsername(username);
    ds.setPassword(password);
    ds.setInitialSize(initialSize);
    ds.setMaxActive(maxActive);
    return ds;
}

Tests测试类

单元测试注解有:  @BeforeClass ,@Before,@Test,@After,@AfterClass

  • @Before:初始化方法对于每一一个测试方法都要执行一次(注意与BeforeClass区别,后者是对于所有方法执行一-次)
  • @After:释放资源对于每一个测试方法都要执行一次(注意与AfterClass区别,后者是对于所有方法执行一-次)
  • @Test:测试方法,在这里可以测试期望异常和超时时间
  • @Test(expected=ArithmeticException. class)检查被测方法是否抛出ArithmeticException异常
  • @Ignore:忽略的测试方法
  • @BeforeClass:针对所有测试,只执行一次, 且必须为static void
  • @AfterClass:针对所有测试,只执行一-次, 且必须为static void
  • -个JUnit4的单元测试用例执行顺序为:
  • @BeforeClass > @Before > @Test > @After > @AfterClass;
  • 每一个测试方法的调用顺序为:
  • @Before > @Test -> @After;
     

接下来,在src/test/java下创建cn.tedu.mybatis包,并在这个包中创建Tests测试类,在类中添加测试方法:

单元测试方法的声明规范:

  1.   必须添加@Test注解;

  2.   必须使用public权限;

  3.   必须使用void作为返回值类型;

  4.   必须保持空参数列表(不允许有参数)

package cn.tedu.mybatis;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Tests {
	
	// 关于4.x系列单元测试方法的声明:
	// 1. 必须添加@Test注解;
	// 2. 必须使用public权限;
	// 3. 必须使用void作为返回值类型;
	// 4. 必须保持空参数列表(不允许有参数)
	@Test
	public void contextLoads() {
		System.out.println("Tests.contextLoads()");
	}
	
	@Test
	public void getConnection() throws SQLException {
		AnnotationConfigApplicationContext ac
			= new AnnotationConfigApplicationContext(SpringConfig.class);
		
		DataSource dataSource = ac.getBean("dataSource", DataSource.class);
		
		Connection conn = dataSource.getConnection();
		System.out.println(conn);
		
		ac.close();
	}

}

如果以上单元测试可以正常通过,则表示连接数据库的相关配置均正确,后续,框架就可以通过以上配置的对象自动连接到数据库。

创建数据表

tedu_ums数据库中创建t_user数据表:

CREATE TABLE t_user (
	id int AUTO_INCREMENT,
    username varchar(20) NOT NULL UNIQUE,
    password varchar(20) NOT NULL,
    age int,
    phone varchar(20),
    email varchar(30),
    PRIMARY KEY (id)
) DEFAULT CHARSET=utf8mb4;

插入数据

 

 

定义抽象方法

当使用MyBatis框架处理增删改查时,抽象方法必须定义在接口中,通常,接口的名称建议使用Mapper作为最后一个单词。

cn.tedu.mybatis包中创建UserMapper接口,这个接口就专门用于声明访问“用户”数据表中的数据:

public interface UserMapper {}

然后,在接口中声明“插入用户数据”的抽象方法,关于抽象方法的声明:

  • 【返回值】如果需要执行的数据操作是增、删、改类型的,则使用Integer作为返回值类型,表示受影响的行数,其实,也可以使用void作为返回值类型,表示“不关心受影响的行数”,但是,不建议这么做;如果需要执行的数据操作是查询,则设计为所期望的类型即可,当然,该类型需要能够将查询到的数据封装进去;

  • 【方法名称】自定义;

  • 【参数列表】根据需要执行的SQL语句中的参数来决定。

当需要执行“插入用户数据”操作时,需要执行的SQL语句大致是

INSERT INTO t_user (username, password, age, phone, email) VALUES (?,?,?,?,?)

可以将以上SQL语句中的参数全部声明到抽象方法的参数列表中,例如:

Integer insert(String username, String password, Integer age, String phone, String email);

或者,也可以将SQL语句中的参数全部声明到某个实体类,然后使用实体类作为抽象方法的参数,例如在cn.tedu.mybatis包下创建User类:

package cn.tedu.mybatis;

public class User {

	private Integer id;
	private String username;
	private String password;
	private Integer age;
	private String phone;
	private String email;

	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 String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + ", age=" + age + ", phone="
				+ phone + ", email=" + email + "]";
	}

}

然后,设计抽象方法为:

Integer insert(User user);

目前,MyBatis框架并不知道接口文件的位置,就更加无法使用自定义的抽象方法,必须在配置类的声明之前添加@MapperScan注解,以指定接口文件所在的包!

配置SQL语句

 

在接口的抽象方法的声明之前,根据需要执行的SQL语句的种类,选择使用@Insert / @Delete / @Update / @Select这4个当中的某个注解,当前已经添加的抽象方法Integer insert(User user);需要执行的是INSERT类型的SQL语句,则需要使用@Insert注解!

然后,在注解中,配置字符串类型的参数,该参数就是需要执行的SQL语句,在SQL语句中,所有的参数都使用#{}格式的占位符,在占位符的大括号内是参数User类的属性名:

@Insert("INSERT INTO t_user (username, password, age, phone, email) VALUES (#{username}, #{password}, #{age}, #{phone}, #{email})")
Integer insert(User user);

配置SqlSessionFactoryBean的对象

MyBatis框架能够自动获取数据库连接,并完成数据访问

最后,还需要在配置类中配置SqlSessionFactoryBean的对象,为该对象设置数据源,使得MyBatis框架能够自动获取数据库连接,并完成数据访问!所以,在SpringConfig类中添加:

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    return bean;
}

UserMapperTests测试类

最后,在src/test/javacn.tedu.mybatis包下创建UserMapperTests测试类,并测试以上方法:

package cn.tedu.mybatis;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class UserMapperTests {
	
	@Test
	public void insert() {
		AnnotationConfigApplicationContext ac
			= new AnnotationConfigApplicationContext(SpringConfig.class);
		
		UserMapper userMapper 
			= ac.getBean("userMapper", UserMapper.class);
		
		User user = new User();
		user.setUsername("spring");
		user.setPassword("1234");
		user.setAge(26);
		user.setPhone("1380138000");
		user.setEmail("[email protected]");
		Integer rows = userMapper.insert(user);
		System.out.println("rows=" + rows);
		
		ac.close();
	}

}

获取自动编号的ID值

@Options(useGeneratedKeys=true, keyProperty="id")

在抽象方法的上方,补充添加@Options注解并进行配置,使得可以获取自动编号的ID值,例如:

@Insert("INSERT INTO t_user (username, password, age, phone, email) VALUES (#{username}, #{password}, #{age}, #{phone}, #{email})")
@Options(useGeneratedKeys=true, keyProperty="id")
Integer insert(User user);

以上在@Options注解中,配置的useGeneratedKeys=true表示“需要获取自动生成的值”,keyProperty表示将获取到的ID值放到参数对象的id属性中去!

删除用户数据

  • 根据id删除用户数据

 

需要执行的SQL语句大致是:

DELETE FROM t_user WHERE id=?

先在UserMapper接口中添加抽象方法: 然后,在抽象方法的声明之前添加@Delete注解来配置SQL语句:

@Delete("DELETE FROM t_user WHERE id=#{id}")
Integer deleteById(Integer id);

最后,编写并执行单元测试:

@Test
public void deleteById() {
    AnnotationConfigApplicationContext ac
        = new AnnotationConfigApplicationContext(SpringConfig.class);

    UserMapper userMapper 
        = ac.getBean("userMapper", UserMapper.class);

    Integer id = 1;
    Integer rows = userMapper.deleteById(id);
    System.out.println("rows=" + rows);

    ac.close();
}

修改用户数据

  • 将所有用户的密码全部改为某个值

需要执行的SQL语句大致是:

UPDATE t_user SET password=?

先在UserMapper接口中添加抽象方法: 然后,在抽象方法的声明之前添加@Update注解来配置SQL语句:

@Update("UPDATE t_user SET password=#{password}")
Integer updatePassword(String password);

@Before:初始化方法对于每一一个测试方法都要执行一次

@After:释放资源对于每一个测试方法都要执行一次

测试用例执行顺序为

@Before > @Test > @After

将测试类中重复代码进行封装

// ------------- 以下代码不需要再调整 -------------

private UserMapper userMapper;
private AnnotationConfigApplicationContext ac;

@Before
public void doBefore() {
	ac = new AnnotationConfigApplicationContext(SpringConfig.class);
	userMapper = ac.getBean("userMapper", UserMapper.class);
}

@After
public void doAfter() {
	ac.close();
}

最后,编写并执行单元测试:

private UserMapper userMapper;
private AnnotationConfigApplicationContext ac;

@Before
public void doBefore() {
    ac = new AnnotationConfigApplicationContext(SpringConfig.class);
    userMapper = ac.getBean("userMapper", UserMapper.class);
}

@After
public void doAfter() {
    ac.close();
}

@Test
public void updatePassword() {
    String password = "88888888";
    Integer rows = userMapper.updatePassword(password);
    System.out.println("rows=" + rows);
}

统计数量

@Select("SELECT COUNT(*) FROM t_user")
Integer count();

编写并执行单元测试:

@Test
public void count() {
	Integer count = userMapper.count();
	System.out.println("count=" + count);
}

查询用户信息

  • 根据id查询某用户的详情
@Select("SELECT * FROM t_user WHERE id=#{id}")
User findById(Integer id);

编写并执行单元测试: 

@Test
public void findById() {
	Integer id = 900;
	User user = userMapper.findById(id);
	System.out.println(user);
}

注意:当查询某1条数据,且没有匹配的查询结果时,将返回null

  • 查询所有用户的信息

@Select("SELECT * FROM t_user ORDER BY id")
List<User> findAll();

编写并执行单元测试: 

@Test
public void findAll() {
	List<User> users = userMapper.findAll();
	System.out.println("count=" + users.size());
	for (User user : users) {
		System.out.println(user);
	}
}

猜你喜欢

转载自blog.csdn.net/c202003/article/details/107192724