最新更新
相关代码已上传到Gitee,欢迎start!
https://gitee.com/the_efforts_paid_offf/java/tree/master/ssm_db1
前言
今天复习Java数据库编程,二话不说MyBatis手把手保姆级教程献上,再也不用担心学不会!
资料:
链接:https://pan.baidu.com/s/1FIDi_9QiTuhb4x7pksGOUQ
提取码:kevf
1. MyBatis入门
1.1 概述
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理注册驱动、创建Connection、创建Statement、手动设置参数、结果集检索及映射等繁杂的过程代码。
- 历史进程
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对iBatis进行一些改进。
- 多学一招
同层产品:commons-dbutils、spring-jdbc、Hibernate
1.2 下载
MyBaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases
- 可以直接Copy老师的JAR包
1.3 与JDBC对比
- JDBC编写DAO的步骤
- MyBatis编写DAO的步骤
1.4 入门案例:搭建环境
1.4.1 构建项目
- 1)创建新项目:Java --> Java EE --> Web Application
- 2)创建项目名:mybatis-demo01
- 3)添加jar包
WEB-INF/lib
目录下(目录不存在,需手动创建)
- 4)添加jar
1.4.2 数据库和表:User
# 创建数据库 CREATE DATABASE ssm_db1; # 使用数据库 USE ssm_db1; # 1.1 创建用户表 CREATE TABLE `user` ( `uid` VARCHAR(32) NOT NULL, `username` VARCHAR(20) DEFAULT NULL, #用户名 `password` VARCHAR(32) DEFAULT NULL, #密码 `name` VARCHAR(20) DEFAULT NULL, #昵称 `email` VARCHAR(30) DEFAULT NULL, #电子邮箱 `telephone` VARCHAR(20) DEFAULT NULL, #电话 `birthday` DATE DEFAULT NULL, #生日 `sex` VARCHAR(10) DEFAULT NULL, #性别 `state` INT(11) DEFAULT 0, #状态:0=未激活,1=已激活 `code` VARCHAR(64) DEFAULT NULL, #激活码 PRIMARY KEY (`uid`) ) ; # 1.2 初始化用户默认数据 INSERT INTO `user` VALUES ('u001','jack','1234','杰克','jack@czxy.com','13612345678','2015-11-04','男',0,NULL); INSERT INTO `user` VALUES ('u002','rose','1234','肉丝','rose@czxy.com','13612345679','2015-11-05','女',0,NULL); INSERT INTO `user` VALUES ('373eb242933b4f5ca3bd43503c34668b','ccc','ccc','aaa','bbb@store.com','15723689921','2015-11-04','男',0,'9782f3e837ff422b9aee8b6381ccf927bdd9d2ced10d48f4ba4b9f187edf7738'),('3ca76a75e4f64db2bacd0974acc7c897','bb','bb','张三','bbb@store.com','15723689921','1990-02-01','男',0,'1258e96181a9457987928954825189000bae305094a042d6bd9d2d35674684e6'),('62145f6e66ea4f5cbe7b6f6b954917d3','cc','cc','张三','bbb@store.com','15723689921','2015-11-03','男',0,'19f100aa81184c03951c4b840a725b6a98097aa1106a4a38ba1c29f1a496c231'),('c95b15a864334adab3d5bb6604c6e1fc','bbb','bbb','老王','bbb@store.com','15712344823','2000-02-01','男',0,'71a3a933353347a4bcacff699e6baa9c950a02f6b84e4f6fb8404ca06febfd6f'),('f55b7d3a352a4f0782c910b2c70f1ea4','aaa','aaa','小王','aaa@store.com','15712344823','2000-02-01','男',1,NULL);
1.5 入门案例:查询所有
1.5.1 JavaBean:User
package com.czxy.ssm.domain; import java.util.Date; /** * Create Table CREATE TABLE `user` ( `uid` varchar(32) NOT NULL, `username` varchar(20) DEFAULT NULL, `password` varchar(20) DEFAULT NULL, `name` varchar(20) DEFAULT NULL, `email` varchar(30) DEFAULT NULL, `birthday` date DEFAULT NULL, `sex` varchar(10) DEFAULT NULL, `state` int(11) DEFAULT NULL, `code` varchar(64) DEFAULT NULL, PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 */ public class User { private String uid; private String username; private String password; private String name; private String email; private Date birthday; private String sex; private Integer state; private String code; @Override public String toString() { return "User{" + "uid='" + uid + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + ", name='" + name + '\'' + ", email='" + email + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", state=" + state + ", code='" + code + '\'' + '}'; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } 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 String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } 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 Integer getState() { return state; } public void setState(Integer state) { this.state = state; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public User(String uid, String username, String password, String name, String email, Date birthday, String sex, Integer state, String code) { this.uid = uid; this.username = username; this.password = password; this.name = name; this.email = email; this.birthday = birthday; this.sex = sex; this.state = state; this.code = code; } public User() { } }
1.5.2 编写Dao:UserMapper
之前的开发中我们编写的都是UserDao,在MyBatis将dao称为Mapper。
所以此后所有dao接口统一命名成Mapper。
- 在MyBatis只需要编写接口即可,实现类由MyBatis自动生成,并在测试程序时自动执行。
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.User; import org.apache.ibatis.annotations.Select; import java.util.List; /** * @author manor的大数据之路 * */ public interface UserMapper { /** * 查询所有 * @return */ @Select("select * from user") public List<User> selectAll(); }
1.5.3 编写核心配置文件:SqlMapConfig.xml
- 配置文件名称:SqlMapConfig.xml
- 配置文件位置:src
- 配置文件内容:
<?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> <!-- 环境: default的值引用什么id,就表示使用什么数据库了--> <environments default="db1"> <!-- 配置数据库连接信息及事务 --> <environment id="db1"> <!-- 表示使用事务:默认是自动开启事务 --> <transactionManager type="JDBC" /> <!-- 使用连接池 --> <dataSource type="POOLED"> <!-- 数据库连接基本信息 --> <property name="driver" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/ssm_db1" /> <property name="username" value="root" /> <property name="password" value="1234" /> </dataSource> </environment> </environments> <mappers> <!-- 表示加载此包下的所有dao接口--> <package name="com.czxy.ssm.mapper"/> </mappers> </configuration>
1.5.4 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; 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 manor的大数据之路 * */ public class Test01_SelectAll { public static void main(String[] args) throws IOException { //1 加载配置文件 // 1.1 获得资源流 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 1.2 获得工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //2 获得会话(连接) SqlSession session = factory.openSession(); //3获得功能接口 UserMapper userMapper = session.getMapper(UserMapper.class); //4 调用功能 List<User> userList = userMapper.selectAll(); //5 打印查询结果 for (User user : userList) { System.out.println(user); } } }
1.6 总结
- 到这里MyBatis的入门案例已经完成。我们总结一下:
- 编写SqlMapConfig.xml,用于配置数据源和需要加载的Mapper
- 编写UserMapper.java接口,用于执行方法与SQL语句的绑定
- 基本API使用,流程是:加载资源、获得工厂、获得会话、获得Mapper。
2. 基本操作:增删改查
2.1 模糊查询
- 功能接口中的方法
- 如果参数简单类型,sql语句需要使用value [不推荐]
@Select("select * from user where name like #{value}") public List<User> selectByName(String name);
- 如果使用@Param,可以进行相应的命名 【推荐】
@Select("select * from user where name like #{name}") public List<User> selectByName(@Param("name") String name);
- 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; 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 manor的大数据之路 * */ public class Test02_Like { public static void main(String[] args) throws IOException { //1 加载配置文件 // 1.1 获得资源流 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 1.2 获得工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //2 获得会话(连接) SqlSession session = factory.openSession(); //3获得功能接口 UserMapper userMapper = session.getMapper(UserMapper.class); //4 调用功能 List<User> userList = userMapper.selectByName("%王%"); //5 打印查询结果 for (User user : userList) { System.out.println(user); } } }
2.2 插入数据
- 功能接口中的方法
/** * 插入数据 * @param user */ @Insert("insert into user(uid, username, password, name, email, birthday, sex, state) values(#{uid},#{username},#{password},#{name},#{email},#{birthday},#{sex},#{state})") public Integer insert(User user);
- 测试类(注意:需要提交事务)
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; 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.Date; import java.util.List; /** * @author manor的大数据之路 * */ public class Test03_Insert { public static void main(String[] args) throws IOException { //1 加载配置文件 // 1.1 获得资源流 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 1.2 获得工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //2 获得会话(连接) SqlSession session = factory.openSession(); //3获得功能接口 UserMapper userMapper = session.getMapper(UserMapper.class); //4 调用功能 User user = new User(); user.setUid("1"); user.setUsername("jack"); user.setPassword("1234"); user.setName("杰克"); user.setEmail("itcast_lt@163.com"); user.setBirthday(new Date()); user.setSex("男"); user.setSex("0"); Integer result = userMapper.insert(user); System.out.println(result); //5 提交资源 session.commit(); //6 释放资源 session.close(); } }
2.3 更新数据
- 功能接口中的方法
/** * 插入数据 * @param user */ @Insert("update user set username=#{username}, password=#{password}, name=#{name}, email=#{email},birthday=#{birthday},sex=#{sex}, state=#{state} where uid=#{uid}") public Integer update(User user);
- 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; 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.Date; /** * @author manor的大数据之路 * */ public class Test04_Update { public static void main(String[] args) throws IOException { //1 加载配置文件 // 1.1 获得资源流 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 1.2 获得工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //2 获得会话(连接) SqlSession session = factory.openSession(); //3获得功能接口 UserMapper userMapper = session.getMapper(UserMapper.class); //4 调用功能 User user = new User(); user.setUid("1"); user.setUsername("jack1"); user.setPassword("12341"); user.setName("杰克"); user.setEmail("itcast_lt@163.com"); user.setBirthday(new Date()); user.setSex("男"); user.setSex("0"); Integer result = userMapper.update(user); System.out.println(result); //5 提交资源 session.commit(); //6 释放资源 session.close(); } }
2.4 删除数据
- 功能接口中的方法
/** * 通过id删除 * @param uid */ @Delete("delete from user where uid = #{uid}") public Integer deleteByPrimaryKey(@Param("uid") Integer uid);
- 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; 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.Date; /** * @author manor的大数据之路 * */ public class Test05_Delete { public static void main(String[] args) throws IOException { //1 加载配置文件 // 1.1 获得资源流 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 1.2 获得工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //2 获得会话(连接) SqlSession session = factory.openSession(); //3获得功能接口 UserMapper userMapper = session.getMapper(UserMapper.class); //4 调用功能 Integer result = userMapper.deleteByPrimaryKey(1); System.out.println(result); //5 提交资源 session.commit(); //6 释放资源 session.close(); } }
3.日志与工具类
3.1 日志
3.1.1 什么是日志
- 记录程序运行的过程细节。例如:我们在控制台可以看到SQL语句
3.1.2 整合日志
- 1)添加jar包 (已添加)
- 2)添加配置文件
# 2. 输出格式 ## log4j.appender.stdout=输出位置(固定值,由log4j提供) ## log4j.appender.stdout.Target=方式 ## log4j.appender.stdout.layout=布局(固定值) ## log4j.appender.stdout.layout.ConversionPattern=格式 # 2.1 将日志输出到控制台 log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c:%L - %m%n # 2.2 将日志输出到文件 log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=d:/file.log log4j.appender.file.Append=false log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c:%L - %m%n #1.log4j.rootLogger=日志级别, 输出方式1, 输出方式2, ... ## 日志级别:debug、info、warn、error log4j.rootLogger=debug, stdout, file # 3 自定义日志级别 ## log4j.logger.包=日志级别 #log4j.logger.com.ibatis = debug #log4j.logger.com.ibatis.common.jdbc.SimpleDataSource = debug #log4j.logger.com.ibatis.common.jdbc.ScriptRunner = debug #log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate = debug #log4j.logger.java.sql.Connection = debug #log4j.logger.java.sql.Statement = debug #log4j.logger.java.sql.PreparedStatement = debug #log4j.logger.java.sql.ResultSet =debug log4j.logger.org.apache.ibatis.transaction = info log4j.logger.org.apache.ibatis.io = info log4j.logger.org.apache.ibatis.datasource = info log4j.logger.org.apache.ibatis.logging = info
3.2 工具类
3.2.1 拷贝工具类
- 完成增删改查的时候,我们发现有一些代码大量重复,我们将提供工具类,对重复代码进行简化。
package com.czxy.ssm.utils; 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.InputStream; /** * @author manor的大数据之路 * */ public class MyBatisUtils { // 会话工厂 private static SqlSessionFactory factory; static{ try { // 1.1 加载核心配置文件 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 1.2 获得工厂 factory = new SqlSessionFactoryBuilder().build(is); } catch (Exception e) { throw new RuntimeException(e); } } private static ThreadLocal<SqlSession> local = new ThreadLocal<>(); /** * 获得新会话 * @return */ private static SqlSession openSession(){ SqlSession sqlSession = local.get(); if(sqlSession == null){ sqlSession = factory.openSession(); local.set(sqlSession); } return sqlSession; } /** * 获得mapper * @param clazz * @return */ public static <T> T getMapper(Class<T> clazz){ return openSession().getMapper(clazz); } /** * 释放资源 */ public static void close() { SqlSession sqlSession = openSession(); if(sqlSession != null){ sqlSession.close(); } } /** * 提交并释放资源 */ public static void commitAndclose() { SqlSession sqlSession = openSession(); if(sqlSession != null){ sqlSession.commit(); close(); } } /** * 回滚并释放资源 */ public static void rollbackAndclose() { SqlSession sqlSession = openSession(); if(sqlSession != null){ sqlSession.rollback(); close(); } } }
3.2.2 工具类原理分析
- 工具类实现原理分析
3.2.3 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.utils.MyBatisUtils; import java.util.Date; /** * @author manor的大数据之路 * */ public class Test06_Utils { public static void main(String[] args) { UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class); User user = new User(); user.setUid("1"); user.setUsername("jack"); user.setPassword("1234"); user.setName("杰克"); user.setEmail("itcast_lt@163.com"); user.setBirthday(new Date()); user.setSex("男"); user.setSex("0"); Integer result = userMapper.insert(user); System.out.println(result); MyBatisUtils.commitAndclose(); } }
4.API详解
4.1 核心配置文件详解
在实际开发中,开发者会事先准备好配置文件模板,然后把模板Copy到项目中,再去修改重要的配置参数即可。这样开发者就无需把配置文件的结构背下来。但是开发者还是需要能够读懂配置文件的。下面我们来学习MyBatis核心配置文件。
4.1.1 根标签:
- 配置子标签时,多个标签之间有先后顺序,使用时一定要注意。
- 如下就是常用4个标签的使用顺序:
<?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></properties> <typeAliases></typeAliases> <environments></environments> <mappers></mappers> </configuration>
- 常见子标签介绍
标签名称 | 描述 |
properties | 属性配置,也可引入外部properties文件 |
settings | 系统参数配置,所有参数都有默认值,通常不用配置 |
typeAliases | 类型别名,简化开发,仅减少类完全限定名的冗余。用于xml开发。 |
plugins | 插件,用于添加扩展功能。 |
environments | 环境配置,提供给factory配置信息 |
mappers | 映射器,确定SQL语句的位置 |
4.1.2 属性:
将易于修改的配置内容抽取到properties中,方便统一管理。mybatis提供两种方式来维护properties:property标签和properties配置文件。
方式1:property标签
- 1)配置:将需要的内容配置在
<properties> <property name="jdbc.driver" value="com.mysql.cj.jdbc.Driver"/> <property name="jdbc.url" value="jdbc:mysql://localhost:3306/ssm_db1"/> <property name="jdbc.username" value="root"/> <property name="jdbc.password" value="1234"/> </properties>
- 2)使用:在配置文件的其他位置,通过
${标识}
方式获得内容
<!-- 使用连接池 --> <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>
- 整体示意图
方式2:properties配置文件
在实际开发中,我们常见数据库的配置信息存放到properties文件,mybatis也提供了对配置文件的支持。
- 1)添加 db.properties配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm_db1 jdbc.username=root jdbc.password=1234
- 2)加载properties文件,修改核心配置文件
<properties resource="db.properties" />
- 整体示意图
注意事项
- properties配置文件加载的内容,将覆盖标签配置的内容。
- 先加载标签配置的内容
- 再加载 resource指定的properties配置文件配置的内容,也就是后者覆盖了前者。
<!--最后url的值为 db.properties配置的内容 --> <properties resource="db.properties" > <property name="jdbc.url" value="jdbc:mysql://localhost:3306/ssm_db2"/> </properties> <!-- 【开发中不建议混搭使用】 -->
4.1.3 设置:
- mybatis框架系统配置settings,用于改变 MyBatis 的运行时行为。
- mybatis提供可多种设置,用于系统的优化。
设置参数 | 描述 | 有效值 | 默认值 |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则映射, 即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | false |
autoMappingBehavior | 指定 MyBatis 是否以及如何自动映射指定的列到字段或属性。 NONE 表示取消自动映射; PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集 | NONE, PARTIAL, FULL | PARTIAL |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要驱动兼容。 | true | false | false |
useColumnLabel | 使用列标签代替列名。 | true | false | true |
cacheEnabled | 该配置影响的所有映射器中配置的缓存的全局开关。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。 | true | false | false |
- 驼峰命名设置
<settings> <!-- java对象属性驼峰,对应数据的下划线 --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
4.1.4 环境:
- MyBatis通过环境environments来配置数据库的连接和事务管理。
- 确定使用哪个配置
<!-- default用于确定当前环境使用哪个配置 <environment id=””>用于提供一套配置方案,id的值提供给default使用。 --> <environments default="配置2"> <environment id="配置1"> </environment> <environment id="配置2"> </environment> </environments>
- 配置内容
<!-- <transactionManager> 用于配置事务管理方案 type:用于确定管理事务具体方案,取值:JDBC、MANAGED JDBC,jdbc底层事务管理,commit提交,rollback回顾。 MANAGED,交予其他框架管理,自己不做事务操作,仅关闭连接。 <dataSource>用于配置连接池(多个连接的池子) type:用于确定管理连接的方案,取值:POOLED、UNPOOLED、JNDI POOLED:通过连接池,管理连接创建和销毁。 UNPOOLED:不使用连接池,每一次都创建和销毁连接。 JNDI:将连接池存放到JNDI中。 --> <environment id="development"> <!-- 使用jdbc管理事务 --> <transactionManager type="JDBC"></transactionManager> <!-- 配置数据源(配置连接) --> <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>
- 扩展(查看源码,可以确定 type 配置内容)
- 事务的配置项
- 连接池的配置项
- MANAGED 不管事务,只关闭连接
4.1.5 映射器:
- 加载指定包package所有的接口。
<!-- 映射文件 --> <mappers> <package name="com.czxy.ssm.mapper"/> </mappers>
4.2 输入:vo 条件查询
在开发中,一个对象的查询条件,比对象中封装的属性更多。例如:user有birthday,我们需要查询2010-2020年的数据,时间段beginTime、endTime在User对象中就没有提供属性,实际开发中,一般提供一个自定义对象,例如:UserVo。
- 1)编写vo
package com.czxy.ssm.vo; /** * @author manor的大数据之路 * */ public class UserVo { private String beginTime; // 开始时间 private String endTime; // 结束时间 public UserVo() { } public UserVo(String beginTime, String endTime) { this.beginTime = beginTime; this.endTime = endTime; } public String getBeginTime() { return beginTime; } public void setBeginTime(String beginTime) { this.beginTime = beginTime; } public String getEndTime() { return endTime; } public void setEndTime(String endTime) { this.endTime = endTime; } }
- 2)修改Mapper,添加 condition 方法
/** * 条件查询 * @param userVo * @return */ @Select("select * from user where birthday >= #{beginTime} and birthday <= #{endTime}") public List<User> condition(UserVo userVo);
- 3)测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.utils.MyBatisUtils; import com.czxy.ssm.vo.UserVo; import java.util.Date; import java.util.List; /** * @author manor的大数据之路 * */ public class Test07_Condition { public static void main(String[] args) { UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class); List<User> list = userMapper.condition(new UserVo("2010-01-01", "2021-01-01")); // 打印 list.forEach(user -> { System.out.println(user); }); MyBatisUtils.commitAndclose(); } }
4.3 输出:结果集映射Result
实际开发中,如果数据库字段和Java对象字段不能对应,就需要我们编写对应关系。
注解 | 描述 |
@Results | 对象和表的映射关系。 |
@Result | 一个对象属性和一个表的字段的映射关系。 |
@ResultMap | 映射关系,使用@Results声明的映射关系。 |
4.3.1 基本使用
- 语法
/** @Results(value = 一组Result ) */ @Results(value = { @Result(property = "属性名", column = "字段名", id = true), @Result(property = "属性名2", column = "字段名2"), @Result(property = "属性名3", column = "字段名3") })
- 基本使用
/** * 查询所有 * @return */ @Select("select * from user") @Results({ @Result(property = "uid", column = "uid", id = true), @Result(property = "username", column = "username"), @Result(property = "password", column = "password") }) public List<User> selectAll();
4.3.2 重复使用
- 语法
@Select(...) @Results(id = "标识", value = {...}) public 返回值 方法名(); @Select(...) @ResultMap("标识") public 返回值 方法名2();
- 使用
/** * 查询所有 * @return */ @Select("select * from user") @Results(id = "userResult", value = { @Result(property = "uid", column = "uid", id = true), @Result(property = "username", column = "username"), @Result(property = "password", column = "password") }) public List<User> selectAll(); /** * 通过id查询详情 * @param uid * @return */ @Select("select * from user where uid = #{uid}") @ResultMap("userResult") public User selectById(@Param("uid") String uid);
4.4 已有注解总结
注解名称 | 描述 |
@Insert | 添加sql |
@Update | 更新sql |
@Delete | 删除sql |
@Select | 查询sql |
@Param | 形参命名 |
@Results | 对象和表的映射关系。 |
@Result | 一个对象属性和一个表的字段的映射关系。 |
5. 关联查询:一对多
5.1 用户和订单数据模型
5.1.1 表关系
CREATE TABLE `orders` ( `oid` VARCHAR(32) PRIMARY KEY NOT NULL, `ordertime` DATETIME DEFAULT NULL, #下单时间 `total_price` DOUBLE DEFAULT NULL, #总价 `state` INT(11) DEFAULT NULL, #订单状态:1=未付款;2=已付款,未发货;3=已发货,没收货;4=收货,订单结束 `address` VARCHAR(30) DEFAULT NULL, #收获地址 `name` VARCHAR(20) DEFAULT NULL, #收获人 `telephone` VARCHAR(20) DEFAULT NULL, #收货人电话 `uid` VARCHAR(32) DEFAULT NULL, CONSTRAINT `order_fk_0001` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ) ; INSERT INTO `orders` VALUES ('x001','2010-10-10',10,1,'江苏','张三','12345','u001'); INSERT INTO `orders` VALUES ('x002','2010-11-11',20,2,'河北','李四','67890','u001'); INSERT INTO `orders` VALUES ('x003','2011-10-10',30,3,'山西','王五','66666','u002')
5.1.2 JavaBean
- 默认情况下,两个JavaBean没有关系
package com.czxy.ssm.domain; import java.util.Date; /** * Create Table CREATE TABLE `orders` ( `oid` varchar(32) NOT NULL, `ordertime` datetime DEFAULT NULL, `total` double DEFAULT NULL, `state` int(11) DEFAULT NULL, `address` varchar(30) DEFAULT NULL, `name` varchar(20) DEFAULT NULL, `telephone` varchar(20) DEFAULT NULL, `uid` varchar(32) DEFAULT NULL, PRIMARY KEY (`oid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 */ public class Order { private String oid; // 订单编号 private Date ordertime; // 下单时间 private Double total; // 订单总金额 private Integer state; // 订单状态 0 未支付 1 已支付 2已发货 3已收货 private String address; // 收货人地址 private String name; // 收货人姓名 private String telephone; // 收货人电话 private String uid; @Override public String toString() { return "Order{" + "oid='" + oid + '\'' + ", ordertime=" + ordertime + ", total=" + total + ", state=" + state + ", address='" + address + '\'' + ", name='" + name + '\'' + ", telephone='" + telephone + '\'' + ", uid='" + uid + '\'' + '}'; } public String getOid() { return oid; } public void setOid(String oid) { this.oid = oid; } public Date getOrdertime() { return ordertime; } public void setOrdertime(Date ordertime) { this.ordertime = ordertime; } public Double getTotal() { return total; } public void setTotal(Double total) { this.total = total; } public Integer getState() { return state; } public void setState(Integer state) { this.state = state; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public Order(String oid, Date ordertime, Double total, Integer state, String address, String name, String telephone, String uid) { this.oid = oid; this.ordertime = ordertime; this.total = total; this.state = state; this.address = address; this.name = name; this.telephone = telephone; this.uid = uid; } public Order() { } }
5.1.3 JavaBean关系
- 以对象的方法,描述两个JavaBean之间的关系
- JavaBean:User
public class User { private String uid; private String username; private String password; private String name; private String email; private Date birthday; private String sex; private Integer state; private String code; // 一对多:一个用户 拥有【多个用户】 private List<Order> orderList = new ArrayList<>(); // ... }
- JavaBean:Order
public class Order { private String oid; // 订单编号 private Date ordertime; // 下单时间 private Double total; // 订单总金额 private Integer state; // 订单状态 0 未支付 1 已支付 2已发货 3已收货 private String address; // 收货人地址 private String name; // 收货人姓名 private String telephone; // 收货人电话 private String uid; // 多对一, 多个订单 属于 【一个用户】 private User user; // ... }
5.2 一对多
5.2.1 语法
在Mybatis注解开发中,需要通过@Result进行关联关系的描述。
- 一对多:需要使用many属性和@Many注解。
@Result( property = "1表JavaBean属性名", column = "1表字段名", many = @Many(select = "多表Mapper的方法签名") )
5.2.2 需求&分析
- 需求:查询用户的同时,查询每个用户对应的订单
- 分析:
- 修改OrderMapper,完成通过uid查询所有的订单
- 修改UserMapper,完成查询用户信息时,查询对应的订单
5.2.3 订单功能:通过uid查询所有的订单
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.Order; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; /** * @author manor的大数据之路 * */ public interface OrderMapper { /** * 通过id查询详情 * @param uid * @return */ @Select("select * from orders where uid = #{uid}") public Order findOrdersByUserId(@Param("uid") String uid) ; }
5.2.4 用户功能:关联查询
public interface UserMapper { /** * 查询所有 * @return */ @Select("select * from user") @Results(id = "userResult", value = { @Result(property = "uid", column = "uid", id = true), @Result(property = "username", column = "username"), @Result(property = "password", column = "password"), @Result(property="orderList" , many=@Many(select="com.czxy.ssm.mapper.OrderMapper.findOrdersByUserId"), column="uid") }) public List<User> selectAll(); }
5.3 多对一
5.3.1 语法
在Mybatis注解开发中,需要通过@Result进行关联关系的描述。
- 多对一:需要使用one属性和@One注解
@Result( property = "多表JavaBean属性名", column = "多表字段名", one = @One(select ="1表Mapper的方法签名") )
5.3.2 需求&分析
- 需求:查询订单时,查询关联的用户信息
- 分析:
1)通过user_id查询用户详情
2)通过id查询订单详情
5.4.3 用户功能:通过id查询用户详情(已有)
/** * 通过id查询详情 * @param uid * @return */ @Select("select * from user where uid = #{uid}") @ResultMap("userResult") public User selectById(@Param("uid") String uid);
5.4.4 订单功能:通过id查询订单详情
/** * * @param id * @return */ @Select("select * from orders where oid = #{oid}") @Results({ @Result(property="oid" , column="oid"), @Result(property="ordertime" , column="ordertime"), @Result(property="total" , column="total"), @Result(property="state" , column="state"), @Result(property="address" , column="address"), @Result(property="name" , column="name"), @Result(property="telephone" , column="telephone"), @Result(property="uid" , column="uid"), @Result(property="user" , one=@One(select="com.czxy.ssm.mapper.UserMapper.selectById") , column="uid"), }) public Order selectById(@Param("oid") String id);
6.关联查询:多对多
6.1 学生和老师数据模型
6.1.1 表间关系
#老师表 CREATE TABLE teacher( tid INT PRIMARY KEY, NAME VARCHAR(50) ); #学生表 CREATE TABLE student( sid INT PRIMARY KEY, NAME VARCHAR(50) ); #中间表 CREATE TABLE teacher_student( teacher_id INT , student_id INT, CONSTRAINT ts_t_fk FOREIGN KEY (teacher_id) REFERENCES teacher(tid), CONSTRAINT ts_s_fk FOREIGN KEY (student_id) REFERENCES student(sid) ); INSERT INTO teacher VALUES (1,'肖老师'); INSERT INTO teacher VALUES (2,'马老师'); INSERT INTO student VALUES (1,'张三'); INSERT INTO student VALUES (2,'李四'); INSERT INTO student VALUES (3,'王五'); INSERT INTO teacher_student VALUES (1,1); INSERT INTO teacher_student VALUES (1,2); INSERT INTO teacher_student VALUES (1,3); INSERT INTO teacher_student VALUES (2,1); INSERT INTO teacher_student VALUES (2,2);
6.1.2 JavaBean及其关系
- JavaBean:Student
package com.czxy.ssm.domain; import java.util.ArrayList; import java.util.List; /** * #学生表 * CREATE TABLE student( * sid INT PRIMARY KEY, * NAME VARCHAR(50) * ); * @author manor的大数据之路 * */ public class Student { private Integer sid; private String name; private List<Teacher> teacherList = new ArrayList<>(); public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Teacher> getTeacherList() { return teacherList; } public void setTeacherList(List<Teacher> teacherList) { this.teacherList = teacherList; } @Override public String toString() { return "Student{" + "sid=" + sid + ", name='" + name + '\'' + ", teacherList=" + teacherList + '}'; } }
- JavaBean:Teacher
package com.czxy.ssm.domain; import java.util.ArrayList; import java.util.List; /** * #老师表 * CREATE TABLE teacher( * tid INT PRIMARY KEY, * NAME VARCHAR(50) * ); * @author manor的大数据之路 * */ public class Teacher { private Integer tid; private String name; private List<Student> studentList = new ArrayList<>(); public Integer getTid() { return tid; } public void setTid(Integer tid) { this.tid = tid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Student> getStudentList() { return studentList; } public void setStudentList(List<Student> studentList) { this.studentList = studentList; } @Override public String toString() { return "Teacher{" + "tid=" + tid + ", name='" + name + '\'' + ", studentList=" + studentList + '}'; } }
6.2 多对多:老师–>学生
- 需要根据老师tid查询中间表中,对应的所有学生id
6.2.1 student 映射
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.Student; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; /** * @author manor的大数据之路 * */ public interface StudentMapper { /** * 通过tid查询对应的学生 * @param tid * @return * @throws Exception */ @Select("select * from student s where s.sid in (select student_id from teacher_student where teacher_id = #{tid} )") public Student findStudentByTeacherId(@Param("tid") Integer tid) throws Exception; }
6.2.2 teacher 映射
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.Teacher; import org.apache.ibatis.annotations.*; /** * @author manor的大数据之路 * */ public interface TeacherMapper { @Select("select * from teacher t where t.tid = #{tid}") @Results({ @Result(property="tid" , column="tid"), @Result(property="name" , column="name"), @Result(property="studentList" , many=@Many(select="com.czxy.ssm.mapper.StudentMapper.findStudentByTeacherId") , column="tid"), }) public Teacher selectById(@Param("tid") Integer tid); }
6.2.3 测试
package com.czxy.ssm.test; import com.czxy.ssm.domain.Order; import com.czxy.ssm.domain.Teacher; import com.czxy.ssm.mapper.OrderMapper; import com.czxy.ssm.mapper.TeacherMapper; import com.czxy.ssm.utils.MyBatisUtils; /** * @author manor的大数据之路 * */ public class Test09_SelectTeacher { public static void main(String[] args) { TeacherMapper teacherMapper = MyBatisUtils.getMapper(TeacherMapper.class); Teacher teacher = teacherMapper.selectById(1); // 打印 System.out.println(teacher); MyBatisUtils.commitAndclose(); } }
6.2.4 巩固练习
- 查询所有的老师,并查询老师对应的学生。
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.Teacher; import org.apache.ibatis.annotations.*; import java.util.List; /** * @author manor的大数据之路 * */ public interface TeacherMapper { /** * 通过id查询详情 * @param tid * @return */ @Select("select * from teacher t where t.tid = #{tid}") @Results(id = "teacherResult" , value = { @Result(property="tid" , column="tid"), @Result(property="name" , column="name"), @Result(property="studentList" , many=@Many(select="com.czxy.ssm.mapper.StudentMapper.findStudentByTeacherId") , column="tid"), }) public Teacher selectById(@Param("tid") Integer tid); /** * 查询所有 * @return */ @Select("select * from teacher") @ResultMap("teacherResult") public List<Teacher> selectList(); }
- 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.Teacher; import com.czxy.ssm.mapper.TeacherMapper; import com.czxy.ssm.utils.MyBatisUtils; import java.util.List; /** * @author manor的大数据之路 * */ public class Test10_SelectAllTeacher { public static void main(String[] args) { TeacherMapper teacherMapper = MyBatisUtils.getMapper(TeacherMapper.class); List<Teacher> teacherList = teacherMapper.selectList(); // 打印 teacherList.forEach(teacher -> { System.out.println(teacher); }); MyBatisUtils.commitAndclose(); } }
7.分页查询
MyBatis没有提供分页支持,需要自己编写limit语句。
开发中我们采用PageHelper插件。
7.1 搭建环境
7.1.1 导入jar包
7.1.2 添加插件
<!-- 插件 --> <plugins> <plugin interceptor="com.github.pagehelper.PageHelper"> <!-- 方言 --> <property name="dialect" value="mysql"/> <!-- 设置为true时,使用RowBounds分页会进行count查询 --> <property name="rowBoundsWithCount" value="true"/> </plugin> </plugins>
7.2 语法
1) 设置分页数据 PageHelper.startPage(int pageNum, int pageSize) 参数1:pageNum 第几页 参数2:pageSize 页面显示个数 2) 封装分页结果 PageInfo new PageInfo(查询结果) //创建分页对象 pageInfo.getTotal(), //自动查询总条数 pageInfo.getPages(), //总分页数
7.3 使用
package com.czxy.ssm.test; import com.czxy.ssm.domain.Teacher; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.TeacherMapper; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.utils.MyBatisUtils; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import java.util.List; /** * @author manor的大数据之路 * */ public class Test11_Page { public static void main(String[] args) { UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class); // 设置分页 ** PageHelper.startPage(1,2); // 查询 List<User> users = userMapper.selectAll(); // 获得封装对象 ** PageInfo<User> pageInfo = new PageInfo<>(users); // 打印分页信息 long total = pageInfo.getTotal(); List<User> list = pageInfo.getList(); System.out.println("总条数:" + total); System.out.println("分页数据:"); list.forEach(user -> { System.out.println(user); }); MyBatisUtils.commitAndclose(); } }
8. 通用Mapper
8.1 概述
- 通用Mapper对MyBatis进行简化的第三方工具包。
- 通用Mapper提供了一个名为
Mapper
的接口,用于自动完成单表的增删改查操作。
public interface UserMapper extends Mapper<User> { }
- 如果通用Mapper中的方法不足以满足你的需求,直接添加自定义方法即可。
8.2 搭建环境
8.2.1 导入jar
8.2.2 修改工具类
- 添加内容从官方文档中拷贝
package com.czxy.ssm.utils; 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 tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.common.MySqlMapper; import tk.mybatis.mapper.entity.Config; import tk.mybatis.mapper.mapperhelper.MapperHelper; import java.io.InputStream; /** * @author manor的大数据之路 * */ public class MyBatisUtils { // 会话工厂 private static SqlSessionFactory factory; static{ try { // 1.1 加载核心配置文件 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 1.2 获得工厂 factory = new SqlSessionFactoryBuilder().build(is); } catch (Exception e) { throw new RuntimeException(e); } } private static ThreadLocal<SqlSession> local = new ThreadLocal<>(); /** * 获得新会话 * @return */ private static SqlSession openSession(){ SqlSession sqlSession = local.get(); if(sqlSession == null){ sqlSession = factory.openSession(); //创建一个MapperHelper MapperHelper mapperHelper = new MapperHelper(); //特殊配置 Config config = new Config(); // 设置UUID生成策略 // 配置UUID生成策略需要使用OGNL表达式 // 默认值32位长度:@java.util.UUID@randomUUID().toString().replace("-", "") //config.setUUID(""); // 主键自增回写方法,默认值MYSQL,详细说明请看文档 // config.setIDENTITY("HSQLDB"); // 支持方法上的注解 // 3.3.1版本增加 config.setEnableMethodAnnotation(true); config.setNotEmpty(true); // 序列的获取规则,使用{num}格式化参数,默认值为{0}.nextval,针对Oracle // 可选参数一共3个,对应0,1,2,分别为SequenceName,ColumnName, PropertyName //config.setSeqFormat("NEXT VALUE FOR {0}"); // 设置全局的catalog,默认为空,如果设置了值,操作表时的sql会是catalog.tablename //config.setCatalog(""); // 设置全局的schema,默认为空,如果设置了值,操作表时的sql会是schema.tablename // 如果同时设置了catalog,优先使用catalog.tablename //config.setSchema(""); // 主键自增回写方法执行顺序,默认AFTER,可选值为(BEFORE|AFTER) //config.setOrder("AFTER"); //设置配置 mapperHelper.setConfig(config); // 注册通用tk.mybatis.mapper.common.Mapper接口 - 可以自动注册继承的接口 mapperHelper.registerMapper(Mapper.class); mapperHelper.registerMapper(MySqlMapper.class); // mapperHelper.registerMapper(SqlServerMapper.class); // mapperHelper.registerMapper(IdsMapper.class); //配置完成后,执行下面的操作 mapperHelper.processConfiguration(sqlSession.getConfiguration()); local.set(sqlSession); } return sqlSession; } /** * 获得mapper * @param clazz * @return */ public static <T> T getMapper(Class<T> clazz){ return openSession().getMapper(clazz); } /** * 释放资源 */ public static void close() { SqlSession sqlSession = openSession(); if(sqlSession != null){ sqlSession.close(); } } /** * 提交并释放资源 */ public static void commitAndclose() { SqlSession sqlSession = openSession(); if(sqlSession != null){ sqlSession.commit(); close(); } } /** * 回滚并释放资源 */ public static void rollbackAndclose() { SqlSession sqlSession = openSession(); if(sqlSession != null){ sqlSession.rollback(); close(); } } }
8.3 编写Mapper
- 编写接口,继承tk.mybatis.mapper.common.Mapper接口即可
- 注意:Mapper接口以tk开头
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.User; import tk.mybatis.mapper.common.Mapper; /** * @author manor的大数据之路 * */ public interface UserMapper2 extends Mapper<User> { }
8.4 通用API
- 查询方法
方法名 | 描述 |
T selectOne(T t) | 根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号 |
List select(T t) | 根据实体中的属性值进行查询,查询条件使用等号 |
List selectAll() | 查询全部结果 |
int selectCount(T t) | 根据实体中的属性查询总数,查询条件,使用等号 |
T selectByPrimaryKey(Object key) | 根据主键字段进行查询 |
boolean existsWhithPrimaryKey(Object key) | 根据主键字段查询记录是否存在 |
List selectByExample(Object example) | 根据Example条件进行查询 |
T selectOneByExample(Object example) | 根据Example条件进行查询,只能有一个返回值 |
int selectCountByExample(Object example) | 根据Example条件进行查询记录数 |
- 插入方法
方法名 | 描述 |
int insert(T t) | 保存一个实体,null的属性也会保存,不会使用数据库默认值 |
int intsertSelective(T t) | 保存一个实体,null的属性不会保存,使用数据库默认值 |
- 更新方法
方法名 | 描述 |
int updateByPrimaryKey(T t) | 根据主键更新实体全部字段,null值会被更新 |
int updateByPrimaryKeySelective(T t) | 根据主键更新实体中不为null值的字段 |
- 删除方法
方法名 | 描述 |
int delete(T t) | 根据实体属性作为条件进行删除,查询条件使用等号 |
int deletePrimaryKey(Object key) | 根据主键字段进行删除 |
int deleteByExample(Object example) | 根据Example条件删除数据 |
8.4.1 通过主键查询
- 1)确定主键,否则所有字段都是主键
- 2)测试
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.mapper.UserMapper2; import com.czxy.ssm.utils.MyBatisUtils; import org.junit.Test; import java.io.IOException; import java.util.List; /** * @author manor的大数据之路 * */ public class Test13_Mapper { @Test public void testSelectByPrimaryKey() { UserMapper2 userMapper2 = MyBatisUtils.getMapper(UserMapper2.class); User user = userMapper2.selectByPrimaryKey("1"); System.out.println(user); MyBatisUtils.commitAndclose(); } }
8.4.2 查询所有
@Test public void testSelectAll() { UserMapper2 userMapper2 = MyBatisUtils.getMapper(UserMapper2.class); List<User> list = userMapper2.selectAll(); // 打印 list.forEach(System.out::println); MyBatisUtils.commitAndclose(); }
8.4.3 添加
@Test public void testInsert() { UserMapper2 userMapper2 = MyBatisUtils.getMapper(UserMapper2.class); User user = new User(); user.setUid("2"); user.setUsername("jack"); user.setPassword("1234"); user.setName("杰克"); user.setEmail("itcast_lt@163.com"); user.setBirthday(new Date()); user.setSex("男"); user.setSex("0"); int result = userMapper2.insert(user); // 打印 System.out.println(result); MyBatisUtils.commitAndclose(); }
8.4.4 修改
@Test public void testUpdate() { UserMapper2 userMapper2 = MyBatisUtils.getMapper(UserMapper2.class); User user = new User(); user.setUid("2"); user.setUsername("jack"); user.setPassword("1234"); user.setName("杰克"); user.setEmail("itcast_lt@163.com"); user.setBirthday(new Date()); user.setSex("男"); user.setSex("0"); int result = userMapper2.updateByPrimaryKey(user); // 打印 System.out.println(result); MyBatisUtils.commitAndclose(); }
8.4.5 删除
@Test public void testDelete() { UserMapper2 userMapper2 = MyBatisUtils.getMapper(UserMapper2.class); int result = userMapper2.deleteByPrimaryKey("2"); // 打印 System.out.println(result); MyBatisUtils.commitAndclose(); }
8.4.6 多条件查询
- 语法:
// 获得多条件对象 Example example = new Example(对象.class); Example.Criteria criteria = example.createCriteria(); // 常见条件方法 andLike() //模糊查询 andEqualTo() //等值查询 andLessThanOrEqualTo() //<=查询 andGreaterThanOrEqualTo() //>=查询 andBetween() //区间查询
@Test public void testCondition() { UserMapper2 userMapper2 = MyBatisUtils.getMapper(UserMapper2.class); Example example = new Example(User.class); Example.Criteria criteria = example.createCriteria(); criteria.andLike("name", "%王%"); criteria.andEqualTo("sex", "男"); List<User> list = userMapper2.selectByExample(example); for (User user : list) { System.out.println(user); } MyBatisUtils.commitAndclose(); }
9. 基于XML
9.1 搭建环境
9.1.1 创建项目
- 1)选择Web 应用
- 2)创建项目mybatis-demo02
9.1.2 添加jar包
9.1.3 拷贝配置类
9.1.4 拷贝工具类
9.1.5 拷贝JavaBean
9.2 入门案例:查询所有
9.2.1 编写流程
- 步骤1:编写Dao接口,用于确定方法名称
- 步骤2:编写Mapper.xml文件,用于编写SQL语句
- 步骤3:编写SqlMapConfig.xml 核心配置文件,并添加mapper xml文件
- 步骤4:测试
9.2.2 编写Mapper接口
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.User; /** * @author manor的大数据之路 * */ public interface UserMapper { /** * 通过id查询详情 * @param uid * @return */ public User selectById(String uid); }
9.2.3 编写Mapper 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.czxy.ssm.mapper.UserMapper"> <select id="selectById" parameterType="string" resultType="com.czxy.ssm.domain.User"> select * from user where uid = #{id} </select> </mapper>
9.2.4 修改核心配置文件
- 核心配置文件 用于确定mapper配置文件的位置
<mappers> <!-- 表示加载此包下的所有dao接口--> <mapper resource="mapper/UserMapper.xml"/> </mappers>
9.2.5 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.utils.MyBatisUtils; import org.junit.Test; /** * @author manor的大数据之路 * */ public class TestUserMapper { @Test public void testSelectById() { UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class); User user = userMapper.selectById("1"); System.out.println(user); MyBatisUtils.commitAndclose(); } }
9.3 配置文件详解
9.3.1 Mapper基本结构
<?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="Mapper类"> <!-- 查询 --> <select id="方法名">SQL语句</select> <!-- 添加 --> <insert id="方法名">SQL语句</insert> <!-- 更新 --> <update id="方法名">SQL语句</update> <!-- 删除 --> <delete id="方法名">SQL语句</delete> </mapper>
9.3.2 Mapper 参数类型:parameterType
- 在映射文件mapper中,我们使用parameterType设置请求参数的类型
<?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="mapper类"> <select id="方法名" parameterType="参数类型">SQL语句</select> </mapper>
- 简单类型:
<!-- 通过id查询 --> <select id="findUserById" parameterType="int" resultType="com.czxy.domain.User"> select * from user where uid = #{id} </select>
- POJO类型:
<!-- 添加用户 --> <insert id="insertUser" parameterType="com.czxy.domain.User"> insert into user(uid, username, password, name, email, birthday, sex, state) values(#{uid},#{username},#{password},#{name},#{email},#{birthday},#{sex},#{state}) </insert>
9.3.3 Mapper 结果类型:resultType
- 在映射文件mapper中,我们使用resultType设置查询结果类型
<?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="mapper类"> <select id="方法名" resultType="结果类型">SQL语句</select> </mapper>
- 简单类型
<!-- 总记录数 --> <select id="findUserCount" resultType="int"> select count(*) from user </select>
- POJO类型
<!-- 通过id查询 --> <select id="findUserById" parameterType="int" resultType="com.czxy.domain.User"> select * from user where uid = #{id} </select>
9.3.4 Mapper 映射关系:ResultMap
- resultType可以指定pojo将查询结果封装到该pojo中,但需要pojo的属性名和sql查询的列名保持一致。
- 如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系。
- 语法:
<!--声明映射--> <resultMap type="JavaBean类型" id="resultMap名称"> <id column="表列名" property="JavaBean属性名"/> <!--用于配置主键的映射--> <result column="表列名" property="JavaBean属性名"/> <!--用于配置普通结果集映射--> </resultMap> <!--使用映射--> <select resultMap="resultMap名称"> </select>
- 实例:
<resultMap type="com.czxy.ssm.domain.User" id="userResultMap"> <id column="uid" property="uid"/> <result column="username" property="username"/> </resultMap> <select id="selectById" parameterType="string" resultMap="userResultMap"> select * from user where uid = #{id} </select>
9.3.5 默认别名
别名 | 映射类型 |
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
map | Map |
9.3.6 自定义别名
- 声明别名,在 SqlMapConfig.xml 配置文件中声明
- 方式1:一次定义一个类
<typeAliases> <typeAlias type="类型" alias="别名"/> </typeAliases>
- 方式2:一次定义一个包下的所有类
<typeAliases> <package name="包名"/> </typeAliases>
- 使用别名,在mapper中直接使用
<!--使用别名--> <select id="selectById" parameterType="string" resultType="user"> select * from user where uid = #{id} </select>
9.3.7 加载Mapper文件
- 在SqlMapConfig.xml文件中,通过
和
加载映射文件
- 方式1:加载指定文件
<mappers> <!-- 表示加载此包下的所有dao接口--> <mapper resource="mapper/UserMapper.xml"/> </mappers>
- 方式2:加载指定包下的所有映射文件
- 要求:要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
<mappers> <package name="com.czxy.ssm.mapper"/> </mappers>
9.4 增删改查
9.4.1 核心配置文件
9.4.2 mapper接口
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.User; import com.czxy.ssm.vo.UserVo; import org.apache.ibatis.annotations.*; import java.util.List; /** * @author manor的大数据之路 * */ public interface UserMapper { /** * 通过id查询详情 * @param uid * @return */ public User selectById(String uid); /** * 查询所有 * @return */ public List<User> selectAll(); /** * 模糊查询 * @param name * @return */ public List<User> selectByName(@Param("name") String name); /** * 插入数据 * @param user */ public Integer insert(User user); /** * 插入数据 * @param user */ public Integer updateByPrimaryKey(User user); /** * 通过id删除 * @param uid */ public Integer deleteByPrimaryKey(@Param("uid") String uid); /** * 条件查询 * @param userVo * @return */ public List<User> condition(UserVo userVo); }
9.4.3 Mapper 映射文件
<?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.czxy.ssm.mapper.UserMapper"> <resultMap type="com.czxy.ssm.domain.User" id="userResultMap"> <id column="uid" property="uid"/> <result column="username" property="username"/> </resultMap> <select id="selectById" parameterType="string" resultMap="userResultMap"> select * from user where uid = #{id} </select> <select id="selectAll" parameterType="string" resultMap="userResultMap"> select * from user </select> <select id="selectByName" parameterType="string" resultMap="userResultMap"> select * from user where name like #{name} </select> <insert id="insert" parameterType="user"> insert into user(uid, username, password, name, email, birthday, sex, state) values(#{uid},#{username},#{password},#{name},#{email},#{birthday},#{sex},#{state}) </insert> <update id="updateByPrimaryKey" parameterType="user"> update user set username=#{username}, password=#{password}, name=#{name}, email=#{email},birthday=#{birthday},sex=#{sex}, state=#{state} where uid=#{uid} </update> <delete id="deleteByPrimaryKey" > delete from user where uid = #{uid} </delete> </mapper>
9.4.4 测试
package com.czxy.ssm.test; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.utils.MyBatisUtils; import org.junit.Test; import java.util.Date; import java.util.List; /** * @author manor的大数据之路 * */ public class TestUserMapper { @Test public void testSelectById() { UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class); User user = userMapper.selectById("1"); System.out.println(user); MyBatisUtils.commitAndclose(); } @Test public void testSelectAll() { UserMapper UserMapper = MyBatisUtils.getMapper(UserMapper.class); List<User> list = UserMapper.selectAll(); // 打印 list.forEach(System.out::println); MyBatisUtils.commitAndclose(); } @Test public void testSelectByName() { UserMapper UserMapper = MyBatisUtils.getMapper(UserMapper.class); List<User> list = UserMapper.selectByName("%张%"); // 打印 list.forEach(System.out::println); MyBatisUtils.commitAndclose(); } @Test public void testInsert() { UserMapper UserMapper = MyBatisUtils.getMapper(UserMapper.class); User user = new User(); user.setUid("2"); user.setUsername("jack"); user.setPassword("1234"); user.setName("杰克"); user.setEmail("itcast_lt@163.com"); user.setBirthday(new Date()); user.setSex("男"); user.setSex("0"); int result = UserMapper.insert(user); // 打印 System.out.println(result); MyBatisUtils.commitAndclose(); } @Test public void testUpdate() { UserMapper UserMapper = MyBatisUtils.getMapper(UserMapper.class); User user = new User(); user.setUid("2"); user.setUsername("jack"); user.setPassword("1234"); user.setName("杰克"); user.setEmail("itcast_lt@163.com"); user.setBirthday(new Date()); user.setSex("男"); user.setSex("0"); int result = UserMapper.updateByPrimaryKey(user); // 打印 System.out.println(result); MyBatisUtils.commitAndclose(); } @Test public void testDelete() { UserMapper UserMapper = MyBatisUtils.getMapper(UserMapper.class); int result = UserMapper.deleteByPrimaryKey("2"); // 打印 System.out.println(result); MyBatisUtils.commitAndclose(); } }
9.5 动态SQL
9.5.1 什么是动态SQL
动态SQL就是Mybatis允许在映射文件中通过标签控制SQL语句最后的拼凑结果。
9.5.2 标签
- 语法:在mapper映射文件中,标签就相当于Java中if语句,如果条件成立,标签体内的SQL语句有效。
<select> <if test="条件"> //有效的SQL语句片段 </if> <select>
- 封装对象:UserVo
public class UserVo { private String name; // 模糊查询 private String beginTime; // 开始时间 private String endTime; // 结束时间 // ... }
- 多条件查询,拼凑恒等条件 where 1=1
<select id="condition" parameterType="userVo" resultType="user" > select * from user where 1=1 <if test="name != null and name != ''"> and name like '%${name}%' </if> </select>
- 测试
@Test public void testCondtion() { UserMapper UserMapper = MyBatisUtils.getMapper(UserMapper.class); UserVo userVo = new UserVo(); userVo.setName("张"); List<User> list = UserMapper.condition(userVo); // 打印 list.forEach(System.out::println); MyBatisUtils.commitAndclose(); }
9.5.3 标签
- 多条件查询时,我们使用了一个小技巧“where 1=1”,mybatis提供了一个
进行取代。
- 修改映射文件
<select id="condition" parameterType="userVo" resultType="user" > select * from user <where> <if test="name != null and name != ''"> and name like '%${name}%' </if> </where> </select>
9.5.4 >标签
语法:
<!-- <foreach> 就是遍历一组数据,根据指定的内容拼凑成SQL语句片段 collection ,需要遍历的数据,如果实际参数就是数组本身,此处需要使用array item ,每一次循环时存放数据的变量,在标签体中可以通过 ${item值}获得遍历数据 open ,SQL语句片段的开发位置 separator,分隔符号 close ,SQL语句片段的结束位置 --> <!-- 例如:uid in (1,2,4,6) 片段的拼凑 开始 (变量 分隔符)*4 结束 --> <foreach collection="数组" open="uid in (" item="变量" separator="," close=")"> </foreach>
封装对象
public class UserVo { private List<String> ids = new ArrayList<>(); private String name; // 模糊查询 private String beginTime; // 开始时间 private String endTime; // 结束时间 // ... }
多条件查询
<select id="condition" parameterType="userVo" resultType="user" > select * from user <where> <!-- uid in (1,2,4,6) --> <foreach collection="ids" open="uid in (" item="id" separator="," close=")"> '${id}' </foreach> </where> </select>
测试
@Test public void testCondtion() { UserMapper UserMapper = MyBatisUtils.getMapper(UserMapper.class); UserVo userVo = new UserVo(); userVo.setIds(Arrays.asList("u001","u002")); List<User> list = UserMapper.condition(userVo); // 打印 list.forEach(System.out::println); MyBatisUtils.commitAndclose(); }
9.5.5 标签:多条件
语法
<select id=""> <choose> <when test=""></when> <when test=""></when> <otherwise></otherwise> </choose> </select>
9.5.6 标签
MyBatis为我们提供了代码片段,使用
定义公共SQL语句,使用
将需要的SQL片段拼凑到指定的位置。
<!-- 所有字段名称SQL片段 --> <sql id="user_all_column">uid, username, password, name, email, birthday, sex, state</sql> <select id="selectAll" parameterType="string" resultMap="userResultMap"> select <include refid="user_all_column" /> from user </select>
9.6 关系映射:一对多
9.6.1 mapper接口
UserMapper,已有
public interface UserMapper { /** * 通过id查询详情 * @param uid * @return */ public User selectById(String uid); }
OrderMapper
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.Order; import org.apache.ibatis.annotations.Param; /** * @author manor的大数据之路 * */ public interface OrderMapper { /** * 查询指定用户的所有的订单 * @param uid * @return */ public Order findOrdersByUserId(@Param("uid") Integer uid) ; }
9.6.2 Mapper 映射文件
OrdersMapper.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.czxy.ssm.mapper.OrderMapper"> <select id="findOrdersByUserId" parameterType="string" resultType="order" > select * from orders where uid = #{uid} </select> </mapper>
UserMapper.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.czxy.ssm.mapper.UserMapper"> <resultMap type="com.czxy.ssm.domain.User" id="userResultMap"> <id column="uid" property="uid"/> <result column="username" property="username"/> <collection property="orderList" column="uid" select="com.czxy.ssm.mapper.OrderMapper.findOrdersByUserId" /> </resultMap> <select id="selectById" parameterType="string" resultMap="userResultMap"> select * from user where uid = #{id} </select> </mapper>
9.6.3 核心配置文件
9.6.4 测试
public class TestUserMapper { @Test public void testSelectById() { UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class); User user = userMapper.selectById("u001"); System.out.println(user); MyBatisUtils.commitAndclose(); } }
9.7 关系映射:多对一
9.7.1 mapper接口
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.Order; import org.apache.ibatis.annotations.Param; import java.util.List; /** * @author manor的大数据之路 * */ public interface OrderMapper { /** * * @param oid * @return */ public Order selectById(@Param("oid") String oid); }
9.7.2 映射文件:OrdersMapper.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.czxy.ssm.mapper.OrderMapper"> <resultMap id="ordersResultMap" type="order"> <id property="oid" column="oid"></id> <result property="ordertime" column="ordertime" ></result> <result property="total" column="total" ></result> <result property="state" column="state" ></result> <result property="address" column="address" ></result> <result property="name" column="name" ></result> <result property="telephone" column="telephone" ></result> <result property="uid" column="uid" ></result> <association property="user" select="com.czxy.ssm.mapper.UserMapper.selectById" column="uid" /> </resultMap> <select id="selectById" resultMap="ordersResultMap"> select * from orders where oid = #{oid} </select> </mapper>
9.7.3 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.Order; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.OrderMapper; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.utils.MyBatisUtils; import com.czxy.ssm.vo.UserVo; import org.junit.Test; import java.util.Arrays; import java.util.Date; import java.util.List; /** * @author manor的大数据之路 * */ public class TestOrderMapper { @Test public void testSelectById() { OrderMapper orderMapper = MyBatisUtils.getMapper(OrderMapper.class); Order order = orderMapper.selectById("x001"); System.out.println(order); MyBatisUtils.commitAndclose(); } } tis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.czxy.ssm.mapper.OrderMapper"> <select id="findOrdersByUserId" parameterType="string" resultType="order" > select * from orders where uid = #{uid} </select> </mapper>
UserMapper.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.czxy.ssm.mapper.UserMapper"> <resultMap type="com.czxy.ssm.domain.User" id="userResultMap"> <id column="uid" property="uid"/> <result column="username" property="username"/> <collection property="orderList" column="uid" select="com.czxy.ssm.mapper.OrderMapper.findOrdersByUserId" /> </resultMap> <select id="selectById" parameterType="string" resultMap="userResultMap"> select * from user where uid = #{id} </select> </mapper>
9.6.3 核心配置文件
[外链图片转存中…(img-emp3n0Qt-1632570480007)]
9.6.4 测试
public class TestUserMapper { @Test public void testSelectById() { UserMapper userMapper = MyBatisUtils.getMapper(UserMapper.class); User user = userMapper.selectById("u001"); System.out.println(user); MyBatisUtils.commitAndclose(); } }
9.7 关系映射:多对一
9.7.1 mapper接口
package com.czxy.ssm.mapper; import com.czxy.ssm.domain.Order; import org.apache.ibatis.annotations.Param; import java.util.List; /** * @author manor的大数据之路 * */ public interface OrderMapper { /** * * @param oid * @return */ public Order selectById(@Param("oid") String oid); }
9.7.2 映射文件:OrdersMapper.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.czxy.ssm.mapper.OrderMapper"> <resultMap id="ordersResultMap" type="order"> <id property="oid" column="oid"></id> <result property="ordertime" column="ordertime" ></result> <result property="total" column="total" ></result> <result property="state" column="state" ></result> <result property="address" column="address" ></result> <result property="name" column="name" ></result> <result property="telephone" column="telephone" ></result> <result property="uid" column="uid" ></result> <association property="user" select="com.czxy.ssm.mapper.UserMapper.selectById" column="uid" /> </resultMap> <select id="selectById" resultMap="ordersResultMap"> select * from orders where oid = #{oid} </select> </mapper>
9.7.3 测试类
package com.czxy.ssm.test; import com.czxy.ssm.domain.Order; import com.czxy.ssm.domain.User; import com.czxy.ssm.mapper.OrderMapper; import com.czxy.ssm.mapper.UserMapper; import com.czxy.ssm.utils.MyBatisUtils; import com.czxy.ssm.vo.UserVo; import org.junit.Test; import java.util.Arrays; import java.util.Date; import java.util.List; /** * @author manor的大数据之路 * */ public class TestOrderMapper { @Test public void testSelectById() { OrderMapper orderMapper = MyBatisUtils.getMapper(OrderMapper.class); Order order = orderMapper.selectById("x001"); System.out.println(order); MyBatisUtils.commitAndclose(); } }