文章目录
1、简介
1.1、什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- 支持定制化 SQL、存储过程以及高级映射
- MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
如何使用Mybatis?
-
Maven依赖导入:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency>
-
中文官方文档: https://mybatis.org/mybatis-3/zh/index.html
什么是框架?
框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种 定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。
1.2、持久化
数据持久化
- 持久化就是将数据在持久状态和瞬时状态转换的过程
- 内存:断电丢失
- 数据库(Jdbc)、io文件持久化
- 就是将容易丢失的数据保存到本地或者数据库中
为什么需要持久化?
- 内存中文件容易丢失,不利于长久保存
- 保存重要数据
1.3、三层架构
- 表现层:是用于展示数据的
- 业务层:是处理业务需求
- 持久层:是和数据库交互的
1.4、持久层
- 完成持久化工作
- 层与层之间界限明显,协同工作
持久层技术的解决方案
- JDBC技术:
- Connection
- PreparedStatement
- ResultSet
- Spring的
JdbcTemplate
: Spring中对jdbc的简单封装 - Apache的
DBUtils
: 对Jdbc的简单封装
1.5、为什么需要Mybatis
- 简化jdbc代码的使用
- 帮助程序使用数据库
- 方便数据库方面的操作
- 优点:
- 使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程。
- sql和代码分离,易于维护
- 提供映射标签,支持对象和数据库字段关系映射
- 提供xml标签,支持动态sql
- 提供对象关系映射标签,支持对象关系组件维护
1.6、ORM是什么
ORM:
Object Relational Mappging 对象关系映射
简单的说:就是把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表。
2、入门案例(day01_01mybatis)
2.1、创建表和插入数据
2.2、导入maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ajacker</groupId>
<artifactId>MyBatisLearn</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>day01_01mybatis</module>
</modules>
<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>8.0.15</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13-beta-3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
2.3、创建实体类和dao的接口
-
User.java
package com.ajacker.domain; import java.io.Serializable; import java.util.Date; /** * @author ajacker */ 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 + '\'' + '}'; } }
-
IUserDao.java
package com.ajacker.dao; import com.ajacker.domain.QueryVo; import com.ajacker.domain.User; import java.util.List; /** * @author ajacker * 用户的持久层接口 */ public interface IUserDao { /** * 查询所有 * @return 查询结果 无为null */ List<User> findAll(); }
2.4、创建主要配置文件
在resources
下创建配置文件
-
SqlMapConifg.xml
(用于配置mybatis
的相关设置)<?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"> <!--配置--> <configuration> <!--引入外部配置文件--> <properties resource="jdbcConfig.properties"/> <!--配置环境,环境可以配置多个,现在默认是mysql--> <environments default="mysql"> <!--配置mysql环境--> <environment id="mysql"> <!--事务管理器--> <transactionManager type="jdbc"/> <!--数据源--> <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> </environment> </environments> <!--映射器--> <mappers> <mapper resource="com/ajacker/dao/IUserDao.xml"/> </mappers> </configuration>
-
jdbcConfig.propertis
(SqlMapConifg.xml
导入了此文件的设置)用于配置数据库信息jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456
2.5、创建映射配置文件
IUserDao.xml
创建在resources
下的和对应类包路径相同的文件夹路径下(com/ajacker/dao/IUserDao.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.ajacker.dao.IUserDao">
<!--配置查询所有-->
<select id="findAll" resultType="com.ajacker.domain.User">
select * from user
</select>
</mapper>
-
注意事项:
-
mapper子标签的标签和查询类型对应,例如
<select>
、<insert>
、<delete>
id
:属性必须是方法名称resultType
:属性标明了返回值类型,是类型的全限定类名或别名
-
namesapce
:是绑定的持久层接口的全限定类名
-
2.6、编写测试类
-
创建测试类
MybatisTest.java
public class MyBatisTest { private InputStream in; private SqlSession sqlSession; private IUserDao userDao; @Before public void init() throws IOException { //1.读取配置文件 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建SqlSessionFactory工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.使用工厂生产SqlSession对象 sqlSession = factory.openSession(); //4.使用SqlSession创建Dao接口的代理对象 userDao = sqlSession.getMapper(IUserDao.class); } @After public void destroy() throws IOException { //提交事务 sqlSession.commit(); //6.释放资源 sqlSession.close(); in.close(); } /** * 测试查询所有 */ @Test public void testFindAll() throws Exception { //5.使用代理对象执行方法 List<User> users = userDao.findAll(); users.forEach(System.out::println); } }
此时运行测试方法可以看见我们准备好的数据已经被全部查询出来了:
3、CURD
3.1、select
选择、查询语句
-
id
:属性必须是方法名称 -
resultType
:属性标明了返回值类型,是类型的全限定类名或别名 -
parameterType
:标明参数类型,是类型的全限定类名或别名
3.1.1、查询所有
-
编写接口:
/** * 查询所有 * @return 查询结果 */ List<User> findAll();
-
编写mapper中对应的sql语句:
<!--配置查询所有--> <select id="findAll" resultType="com.ajacker.domain.User"> select * from user </select>
-
编写测试类测试:
/** * 测试查询所有 */ @Test public void testFindAll() throws Exception { //5.使用代理对象执行方法 List<User> users = userDao.findAll(); users.forEach(System.out::println); }
3.1.2、查询一个
-
编写接口:
/** * 根据id删除查询用户 * @param userId * @return */ User findById(int userId);
-
编写mapper中对应的sql语句:
<!--根据id查询用户--> <select id="findById" parameterType="int" resultType="com.ajacker.domain.User"> select * from user where id=#{uid} </select>
-
编写测试类测试:
/** * 测试查询一个 */ @Test public void testFindOne(){ //查询一个 User user = userDao.findById(1); System.out.println(user); }
3.1.3、聚合函数查询
-
编写接口:
/** * 查询总用户数 * @return */ int findTotal();
-
编写mapper中对应的sql语句:
<!--获取总用户数--> <select id="findTotal" resultType="int"> select count(id) from user </select>
-
编写测试类测试:
/** * 测试查询用户数 */ @Test public void testTotal(){ //查询用户数 int total = userDao.findTotal(); System.out.println(total); }
3.2、insert
-
编写接口:
/** * 保存用户 */ void saveUser(User user);
-
编写mapper中对应的sql语句:
<!--保存用户--> <insert id="saveUser" parameterType="com.ajacker.domain.User"> <!--配置插入后获得插入用户的id,Property对应属性,Column对应数据库列名--> <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>
-
编写测试类测试:
/** * 测试保存 */ @Test public void testSave(){ User user = new User(); user.setUsername("王二狗"); user.setAddress("太原"); user.setSex("女"); user.setBirthday(new Date()); System.out.println("保存之前:"+user); //userDao保存方法 userDao.saveUser(user); System.out.println("保存之后:"+user); }
-
观察结果:
我们可以发现,配置了<selectkey>
在执行了语句之后获得了插入的id并填充给了对象
3.3、update
-
编写接口:
/** * 更新用户 * @param user */ void updateUser(User user);
-
编写mapper中对应的sql语句:
<!--更新用户--> <update id="updateUser" parameterType="com.ajacker.domain.User"> update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id} </update>
-
编写测试类测试:
/** * 测试更新 */ @Test public void testUpdate(){ User user = userDao.findById(11); user.setUsername("test update"); user.setAddress("德阳市"); user.setSex("女"); user.setBirthday(new Date()); //userDao保存方法 userDao.updateUser(user); }
3.4、delete
-
编写接口:
/** * 根据id删除用户 * @param userId */ void deleteUser(int userId);
-
编写mapper中对应的sql语句:
<!--删除用户--> <delete id="deleteUser" parameterType="int"> delete from user where id=#{uid} </delete>
-
编写测试类测试:
/** * 测试删除 */ @Test public void testDelete(){ //userDao删除方法 userDao.deleteUser(4); }
3.5、多参数情况
3.5.1、使用Map传入
-
编写接口:
/** * 插入用户,参数用map包装 * @param map */ void saveUserUseMap(Map<String,Object> map);
-
编写mapper中对应的sql语句:
<!--传入map保存用户--> <update id="saveUserUseMap" parameterType="map"> insert into user(username, address, sex, birthday) values(#{userId},#{userAds},#{userSex},#{userBirth}) </update>
-
编写测试类测试:
/** * 测试保存用户使用map */ @Test public void testSaveUseMap(){ Map<String,Object> map = new HashMap<>(); map.put("userId", "王飒"); map.put("userAds", "江洋大道"); map.put("userBirth", new Date()); //userDao保存方法 userDao.saveUserUseMap(map); }
-
查看结果
- 插入之前:
-
插入之后:
- 可以看到用这种方法,Mybatis以配置文件中的内容为键,去取出参数加入sql语句,这里我们没有设置性别,所以为null
3.5.1、使用@Param注解
-
编写接口
/** * 有限制的查询所有 * @param startIndex * @param limit * @return */ List<User> findAllByLimit(@Param("startIndex") int startIndex, @Param("limit") int limit);
-
编写mapper中对应的sql语句:
<!--配置查询所有限制查询--> <select id="findAllByLimit" resultMap="userMap"> select * from user limit #{startIndex},#{limit} </select>
-
编写测试类测试:
@Test public void testFindAllByLimit(){ List<User> userList = userDao.findAllByLimit(0, 4); userList.forEach(System.out::println); }
- 我们可以看到,使用这种方法,
Mybatis
以注解的属性为引用来寻找对应的属性
3.6、模糊查询
-
编写接口:
/** * 根据名字模糊查询 * @param name * @return */ List<User> findByName(String name);
-
编写mapper中对应的sql语句:
<!--根据名称模糊查询--> <select id="findByName" parameterType="string" resultType="com.ajacker.domain.User"> select * from user where username like #{uname} </select>
-
编写测试类测试:
/** * 测试模糊查询 */ @Test public void testFindByName(){ //模糊查询 List<User> users = userDao.findByName("%王%"); users.forEach(System.out::println); }
-
查询结果:
-
注意事项:
-
可将mapper中对应的语句换成:
<!--根据名称模糊查询--> <select id="findByName" parameterType="string" resultType="com.ajacker.domain.User"> select * from user where username like "%"#{uname}"%" </select>
此时测试类方法传入参数不需要
%
-