一:概念
1、Mybatis 基于java的持久层框架,它的内部封装了JDBC,让开发人员只需要关注SQL语句本 身,不需要花费精力在驱动的加载、连接的创 建、Statement的创建等复杂的过程。
二:基本操作
1、jdbc原来的编程模式:
public class TestJDBC {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT";
//获取连接
conn = DriverManager.getConnection(url, "root", "root");
//SQL语句
String sql = "select * from team;";
ps = conn.prepareStatement(sql);
//执行查询
rs = ps.executeQuery();
//遍历结果集
List<Team> list = new ArrayList<>();
while (rs.next()) {
Team team = new Team();
team.setTeamName(rs.getString("teamName"));
team.setTeamId(rs.getInt("teamId"));
team.setCreateTime(rs.getDate("createTime"));
team.setLocation(rs.getString("location"));
list.add(team);
}
list.forEach(team -> System.out.println(team));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
//关闭资源
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2、采用myBatis进行改进
1)创建数据库
2)创建maven项目,在pom.xml中添加maven依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<!--映射文件所在的目录-->
<directory>src/main/java</directory>
<!--包括目录下的.properties和.xml都会被扫描到-->
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
3)编写mybatis的配置文件myBatis.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">
<configuration>
<!--配置mybatis的环境-->
<environments default="development">
<!--id是数据源的名称-->
<environment id="development">
<!--事务类型:使用JDBC事务,使用connection 的提交和回滚-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源,使用的是数据库中的连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_day01? useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT"/>
<property name="username" value="root"/>
<property name="password" value="zhangjing1234"/>
</dataSource>
</environment>
</environments>
<!--注册映射文件-->
<mappers>
<mapper resource="com/zj/pojo/Team.xml"/>
</mappers>
</configuration>
4)编写实体类
public class TeamTest {
//定义配置文件
private String resource = "mybatis.xml";
@Test
public void test01(){
try {
//读取myBatis的配置文件
Reader reader = Resources.getResourceAsReader(resource);
//创建sqlSessionFactory对象,目的是获取sqlSession----根据图纸创建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建可执行sql语句的sqlSession---工厂创建产品
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行sql语句
List<Object> list = sqlSession.selectList("com.zj.pojo.Team.findAll");
for (Object o : list) {
System.out.println(o);
}
//关闭sqlSession,释放资源
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5)编写ORM映射文件
<?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">
<!--namespace名称,必须和映射的实体类相同,是实体类的完全限定名-->
<mapper namespace="com.zj.pojo.Team">
<!--id 为自定义名称,不可以重复,相当于dao中方法的名字一样
resultType 使用的要求:实体类的属性名必须和表中的列名相同
-->
<!--如果有多个sql语句,则写多个select标签-->
<select id="findAll" resultType="com.zj.pojo.Team">
<!--定义的sql语句-->
select * from Team;
</select>
</mapper>
6)将映射文件注册到myBatis的配置文件myBatis.xml中
<!--注册映射文件-->
<mappers>
<mapper resource="com/zj/pojo/Team.xml"/>
</mappers>
7)在pom.xml文件中,配置映射文件扫描的路径
<resources>
<resource>
<!--映射文件所在的目录-->
<directory>src/main/java</directory>
<!--包括目录下的.properties和.xml都会被扫描到-->
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
8)编写测试类
public class TeamTest {
//定义配置文件
private String resource = "mybatis.xml";
@Test
public void test01(){
try {
//读取myBatis的配置文件
Reader reader = Resources.getResourceAsReader(resource);
//创建sqlSessionFactory对象,目的是获取sqlSession----根据图纸创建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建可执行sql语句的sqlSession---工厂创建产品
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行sql语句
List<Object> list = sqlSession.selectList("com.zj.pojo.Team.findAll");
for (Object o : list) {
System.out.println(o);
}
//关闭sqlSession,释放资源
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三:入门案例的增删改查
1、在Team.xml中添加的sql语句
<?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">
<!--namespace名称,必须和映射的实体类相同,是实体类的完全限定名-->
<mapper namespace="com.zj.pojo.Team">
<!--id 为自定义名称,不可以重复,相当于dao中方法的名字一样
resultType 使用的要求:实体类的属性名必须和表中的列名相同
-->
<!--
入门案例一:查询所有
如果有多个sql语句,则写多个select标签
-->
<select id="findAll" resultType="com.zj.pojo.Team">
<!--定义的sql语句-->
select * from Team;
</select>
<!--
入门案例一:根据ID查询
parameterType="参数的类型",目前只支持一个参数
where teamId=#{id}: #{id}表示参数 id-自定义,只需要符合命名规范即可,没有实际对应意义
-->
<select id="findById" parameterType="java.lang.Integer" resultType="com.zj.pojo.Team">
select * from Team where teamId=#{id}
</select>
<!--
入门案例一:添加
parameterType="com.kkb.pojo.Team" 将对象作为参数,
#{值} 值必须是实体类中的属性名称,其实就是占位符?
-->
<insert id="add" parameterType="com.zj.pojo.Team" >
insert into team(teamName,location,createTime)
value (#{teamName},#{location},#{createTime})
</insert>
<!--
入门案例:更新
-->
<update id="update" parameterType="com.zj.pojo.Team">
update team set teamName = #{teamName},location=#{location} where teamId = #{teamId}
</update>
<!--
入门案例:删除
-->
<delete id="delete" parameterType="java.lang.Integer">
delete from team where teamId = #{teamId}
</delete>
</mapper>
2、编写的测试类
public class TeamTest {
//定义配置文件
private String resource = "mybatis.xml";
private SqlSession sqlSession;
@Before //该注解表示在所有测试方法执行之前执行
public void before() {
try {
//读取配置文件
Reader reader = Resources.getResourceAsReader(resource);
//创建sqlSessionFactory对象,目的地获取sqlSession------根据图纸创建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建可执行sql语句的sqlSession---工厂创建产品
sqlSession = sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
@After //该注解表示在所有测试方法执行之后执行
public void after(){
sqlSession.close();
}
/**
* 测试根据id删除
*/
@Test
public void test05(){
int delete = sqlSession.delete("com.zj.pojo.Team.delete", 1003);
sqlSession.commit();
System.out.println(delete);
}
/**
* 测试根据id修改
*/
@Test
public void test04(){
Team team = sqlSession.selectOne("com.zj.pojo.Team.findById", 1003);
team.setTeamName("zhang");
team.setLocation("chengDu");
int update = sqlSession.update("com.zj.pojo.Team.update", team);
sqlSession.commit();
System.out.println(update);
}
/**
* 测试插入操作
*/
@Test
public void test03(){
Team team = new Team();
team.setTeamName("金牛队");
team.setLocation("旧金山");
team.setCreateTime(new Date());
int insert = sqlSession.insert("com.zj.pojo.Team.add", team);
//增删改都需要手动提交
sqlSession.commit();
System.out.println(insert);
}
/**
* 测试查询所有
*/
@Test
public void test02(){
Team team = sqlSession.selectOne("com.zj.pojo.Team.findById", 1003);
System.out.println(team);
}
/**
* 测试查询所有
*/
@Test
public void test01() {
//执行sql语句
List<Object> list = sqlSession.selectList("com.zj.pojo.Team.findAll");
for (Object o : list) {
System.out.println(o);
}
//关闭sqlSession,释放资源
sqlSession.close();
}
}
3、之前的配置同上
四:日志的使用
1、日志相当于你每一步操作的记录,我们只要在pom.xml中做好日志的配置就可以了
2、在配置文件pom.xml中引入日志的配置文件
3、在main下的resource中创建一个log4j.properties的配置文件
里面的stdout相当于在控制台打印
# Global logging configuration info warning error
log4j.rootLogger=DEBUG,stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
4、在myBatis.xml中配置日志
<!--配置日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
5、结果
五:myBatis对象分析和架构
1、myBatis的对象分析
1)Resources类:顾名思义就是资源类,用于读取资源文件,其中很多方法通过加载解析资源文
件,返回不同对象的IO流。
2)sqlSessionFactoryBuilder类:sqlSessionFactory对象的创建,需要使用sqlSessionFactoryBuilder中的build( )方法来创建。事实上使用SqlSessionFactoryBuilder的原因
2、myBatis架构
六:使用原有的DAO方式开发
1、 创建一个dao包,创建相应的类,和原来一样,在创建一个工具包,因为获取sqlSession和
关闭资源是每个sql操作都要做的事情。
2、创建工具类
public class MyBatisUtil {
private static SqlSession sqlSession;
private static SqlSessionFactory sqlSessionFactory;
/**
* 因为sqlSessionFactory这个对象只用创建一次,所以我们提到静态代码块中来
*/
static{
Reader reader = null;
try {
//1、读取配置文件
reader = Resources.getResourceAsReader("mybatis.xml");
} catch (IOException e) {
e.printStackTrace();
}
//2、创建sqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
/**
* 获取sqlSession
* @return
*/
public static SqlSession getSqlSession(){
//3、创建sqlSession对象
sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
/**
* 关闭资源
*/
public static void closeSqlSession(){
sqlSession.close();
}
}
3、创建dao接口
public interface TeamDao {
//查询所有
List<Team> queryAll();
//查询单个
Team queryById(Integer teamId);
//添加
int add(Team team);
//修改
int update(Team team);
//删除
int delete(Integer teamId);
}
4、创建dao接口实现类
public class TeamDaoImpl implements TeamDao {
@Override
public List<Team> queryAll() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
List<Team> list = sqlSession.selectList("com.zj.pojo.Team.findAll");
return list;
}
@Override
public Team queryById(Integer teamId) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
Team team = sqlSession.selectOne("com.zj.pojo.Team.findById", teamId);
return team;
}
@Override
public int add(Team team) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int insert = sqlSession.insert("com.zj.pojo.Team.add", team);
sqlSession.commit();
return insert;
}
@Override
public int update(Team team) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int update = sqlSession.update("com.zj.pojo.Team.update",team);
sqlSession.commit();
return update;
}
@Override
public int delete(Integer teamId) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int delete= sqlSession.delete("com.zj.pojo.Team.delete",teamId);
sqlSession.commit();
return delete;
}
}
7、使用ThreadLocal优化工具类
1、我们都知道,sqlSession类是线程不安全的,所以我们需要对他进行优化改进。
2、我们通过一个例子来理解认识ThreadLocal
public class ThreadLocalTest {
//定义一个ThreadLocal,ThreadLocal是一个集合,但是他只能存放一个值
private ThreadLocal<String>threadLocal = new ThreadLocal<>();
//定义一个list集合,来和ThreadLocal作比较
private List<String> list = new ArrayList<>();
//创建两个线程
class A extends Thread{
@Override
public void run() {
//向ThreadLocal集合中存入数据
threadLocal.set("王丽娜");
System.out.println("A----"+threadLocal.get());
//向list集合中放数据
list.add("AAA");
System.out.println("A----"+list.get(0));
}
}
class B extends Thread{
@Override
public void run() {
//向ThreadLocal集合中存入数据
threadLocal.set("林黛玉");
System.out.println("B----"+threadLocal.get());
//向list集合中放数据
list.add("BBB");
System.out.println("B----"+list.get(0));
}
}
public static void main(String[] args) {
//创建对象
ThreadLocalTest threadLocalTest = new ThreadLocalTest();
ThreadLocalTest.A a = threadLocalTest.new A();
ThreadLocalTest.B b = threadLocalTest.new B();
a.start();
b.start();
}
}
结果:
从上诉代码和结果中可以看出,list集合的值可以互相取得,但是对于ThreadLacal中的值,每个线程之间不可以互相访问,所以通过这个特性,就可以解决sqlSession线程不安全的问题。
3、用ThreadLocal来优化工具类,解决sqlSession线程不安全的问题。
public class MyBatisUtil {
// private static SqlSession sqlSession;
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
private static SqlSessionFactory sqlSessionFactory;
/**
* 因为sqlSessionFactory这个对象只用创建一次,所以我们提到静态代码块中来
*/
static{
Reader reader = null;
try {
//1、读取配置文件
reader = Resources.getResourceAsReader("mybatis.xml");
} catch (IOException e) {
e.printStackTrace();
}
//2、创建sqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
/**
* 获取sqlSession
* @return
*/
public static SqlSession getSqlSession(){
//从当前线程获取sqlSession线程
SqlSession sqlSession = threadLocal.get();
if(sqlSession==null){
//创建sqlSession
sqlSession = sqlSessionFactory.openSession();
//把sqlSession存入到线程中
threadLocal.set(sqlSession);
}
return sqlSession;
}
/**
* 关闭资源
*/
public static void closeSqlSession(){
//从线程池中获取sqlSession
SqlSession sqlSession = threadLocal.get();
if (sqlSession!=null) {
//关闭sqlSession
sqlSession.close();
//从线程池中移除
threadLocal.remove();
}
}
}
8、使用Mapper的接口编写MyBatis项目
1、在前面例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。
2、MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对DB 进行操作。这种对 Dao 的实现方式 称为 Mapper接口 的动态代理方式。
3、Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。
4、代码实现
4.1)创建一个包mapper,里面包括接口TeamMapper和TeamMapper.xml配置文件
接口:
public interface TeamMapper {
//查询所有
List<Team> queryAll();
//查询单个
Team queryById(Integer teamId);
//添加
int add(Team team);
//修改
int update(Team team);
//删除
int delete(Integer teamId);
}
配置文件:
<?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">
<!--每加一个配置文件,我们都要到mybatis.xml配置文件中去注册-->
<!--namespace名称,必须和映射的实体类相同,接口的完全限定名-->
<mapper namespace="com.zj.mapper.TeamMapper">
<!--id 为自定义名称,不可以重复,相当于dao中方法的名字一样
resultType 使用的要求:实体类的属性名必须和表中的列名相同
-->
<!--
入门案例一:查询所有
如果有多个sql语句,则写多个select标签
-->
<select id="findAll" resultType="com.zj.pojo.Team">
<!--定义的sql语句-->
select * from Team;
</select>
<!--
入门案例一:根据ID查询
parameterType="参数的类型",目前只支持一个参数
where teamId=#{id}: #{id}表示参数 id-自定义,只需要符合命名规范即可,没有实际对应意义
-->
<select id="findById" parameterType="java.lang.Integer" resultType="com.zj.pojo.Team">
select * from Team where teamId=#{id}
</select>
<!--
入门案例一:添加
parameterType="com.kkb.pojo.Team" 将对象作为参数,
#{值} 值必须是实体类中的属性名称,其实就是占位符?
-->
<insert id="add" parameterType="com.zj.pojo.Team" >
insert into team(teamName,location,createTime)
value (#{teamName},#{location},#{createTime})
</insert>
<!--
入门案例:更新
-->
<update id="update" parameterType="com.zj.pojo.Team">
update team set teamName = #{teamName},location=#{location} where teamId = #{teamId}
</update>
<!--
入门案例:删除
-->
<delete id="delete" parameterType="java.lang.Integer">
delete from team where teamId = #{teamId}
</delete>
</mapper>
4.2)创建测试类
public class TeamMapperTest {
//通过动态代理的方式产生实现类
private TeamMapper teamMapper = MyBatisUtil.getSqlSession().getMapper(TeamMapper.class);
@Test
public void findAllTest(){
List<Team> list = teamMapper.findAll();
for (Team team : list) {
System.out.println(team);
}
}
}
5、在实现的过程,你可以将Team.xml 和 TeamMapper.xml配置文件放到resource下面,但是他们要和原来的对应的接口类同包名。
9、Mapper动态代理源码查看
10、获取自增的id值
1、获取 int 类型的
1)插入数据的时候获取自增的id,我们需要到sql语句的配置文件中去添加新的标签
<insert id="add" parameterType="com.zj.pojo.Team" >
<!--新增成功之后将自增的ID赋值给参数属性teamId
keyProperty:表示新增的id值赋值到哪个属性值红
order:AFTER/BEFORE两个取值,表示selectKey中的sql语句在insert语句之前还是之后执行
resultType:表示返回值类型
-->
<selectKey keyProperty="teamId" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID();
</selectKey>
insert into team(teamName,location,createTime)
value (#{teamName},#{location},#{createTime})
</insert>
2)测试类
@Test
public void addTest(){
Team team = new Team();
team.setTeamName("美少女战士");
team.setLocation("富士山");
team.setCreateTime(new Date());
int add = teamMapper.add(team);
sqlSession.commit();
System.out.println(add);
System.out.println(team.getTeamId());
}
2、获取 String 类型的
1)添加一张新表,表的recordId为字符串类型
CREATE TABLE `gamerecord` (
`recordId` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`homeTeamId` INT DEFAULT NULL COMMENT '主队ID',
`gameDate` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '比赛日期',
`score` INT DEFAULT NULL COMMENT '得分',
`visitingTeamId` INT DEFAULT NULL COMMENT '客队ID',
PRY KEY (`recordId`), KEY `homeTeamId` (`homeTeamId`),
KEY `visitingTeamId` (`visitingTeamId`),
CONSTRAINT `gamerecord_ibfk_1` FOREIGN KEY (`homeTeamId`) REFERENCES `team` (`teamId`),
CONSTRAINT `gamerecord_ibfk_2` FOREIGN KEY (`visitingTeamId`) REFERENCES `team` (`teamId`) )ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2) 实体类
public class GameRecord {
private String recordId;
private Integer homeTeamId;
private Date gameDate;
private Integer score;
private Integer visitingTeamId;
//省略set get
}
3)mapper接口
public interface GameRecordMapper {
int add(GameRecord record);
}
4)添加配置文件
<?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>
<insert id="add" parameterType="com.zj.pojo.GameRecord" >
<!--
插入数据之前先获取36位字符串作为id放入属性recordId中
order="AFTER/BEFORE" 在insert执行之前还是之后
resultType="返回值的类型"
-->
<selectKey keyProperty="recordId" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>
INSERT INTO `mybatis`.`gamerecord` (`recordId`, `homeTeamId`, `gameDate`, `score`, `visitingTeamId`)
VALUES (#{recordId}, #{homeTeamId},default, #{score}, #{visitingTeamId})
</insert>
</mapper>
5)编写测试类
private SqlSession sqlSession = MyBatisUtil.getSqlSession();
@Test
public void testAdd() {
GameRecordMapper mapper = sqlSession.getMapper(GameRecordMapper.class);
GameRecord record = new GameRecord();
record.setHomeTeamId(1007);
record.setVisitingTeamId(1002);
record.setScore(118);
int num = mapper.add(record);
sqlSession.commit();
//必须提交才能让增删改生效
System.out.println("add结果:" + num);
System.out.println(record.getRecordId());
}
11、输入映射
1、针对传入的为一个参数:
parameterType是执行操作的类型,比如你只需添加操作,添加进去的就是一个team对象,所以要使用该类的完全限定名。
2、对于传入多个参数,不可以使用parameterType这个属性名,
举个栗子,好吃
1)在接口中定义一个方法
List<Team> queryByRange1(@param("min")Integer min, @param("max")Integer max);
2) 在TeamMapper.xml配置文件中添加该方法的配置内容
<select id="queryByTwoParam" resultType="com.zj.pojo.Team">
<!--方式2:通过注解的方式:
#{}中的名称必须与接口的方法中的参数注解@Param()保持一致
select * from team where teamId >=#{param1} and teamId <= #{param2};
不推荐,但是语法也是正确的,但是不能使用arg0,arg1...... -->
select * from team where teamId>=#{min} and teamId<=#{max};
</select>
3)编写测试类
@Test
public void test02(){
List<Team> teams = teamMapper.queryByRange2(1005, 1011);
teams.forEach(team -> System.out.println(team));
}