Mybatis笔记
采用了ORM思想解决了实体类和数据库表映射的问题。对JDBC进行了封装,屏蔽了JDBCAPI底层的访问细节,避免我们与jdbc的api打交道,就能完成对数据的持久化操作。
O–Object java对象
R- Relation 关系,就是数据库中的一张表
M-mapping 映射
一、Mybatis入门案例
1.创建maven项目,添加Mybatis的jar依赖
<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.23</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
2.编写Mybatis的配置文件
一般情况下:配置文件的名称可以自定义,课程中使用mybatis.xml。配置文件放置在java/resources中。
头文件去官网中复制粘贴。在这里给大家提供一个中文的网站。
https://mybatis.org/mybatis-3/zh/index.html
<?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:创建数据库 Connection 对象 type: POOLED 使用数据库的连接池 --> <dataSource type="POOLED"> <!--连接数据库的四大参数 注意数据库版本使用的是MySQL8,如果是mysql5的话,driver和url都不一样,参考学过的JDBC--> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis? useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration>
3.编写实体类
实体类中的属性必须与表中的列名保持一致。
4.编写ORM映射文件
我们是针对实体类Team.java和表Team进行ORM映射.
Mybatis框架中,ORM映射是针对SQL语句进行,Mybatis框架将SQL语句抽取到了XML中。所以我们需要针对每个实体类编写XML映射文件。
4.1 XML映射文件必须与实体类在同一个包下面(也可以存放在resource资源包下,但是存放的包路径要一致)。
4.2 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"> <!--namespace="名称必须与映射的类的名字一致,是完全限定名"--> <mapper namespace="com.kkb.pojo.Team"> <!-- id="自定义名称,id不能重复;相当于dao中的方法名称" resultType="使用的要求:实体类中的属性名与表中的列名一致" --> <select id="queryAll" resultType="com.kkb.pojo.Team"> select * from team; </select> </mapper>
5.将映射文件注册到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> <environments default="development"> <environment id="development"> ...... </environment> </environments> <!-- 注册映射文件 --> <mappers> <mapper resource="com/kkb/pojo/Team.xml"/> </mappers> </configuration>
6.配置映射文件的扫描位置
pom.xml文件配置映射文件的扫描路径
<build> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml 文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering></resource> </resources> <plugins> //省略 </plugins> </build>
7.使用Mybatis框架的核心接口测试
package com.kkb.test; import com.kkb.pojo.Team; import com.mysql.cj.Session; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.IOException; import java.io.Reader; import java.util.List; /*** ClassName: TeamTest * Team 测试类 * @author wanglina * @version 1.0 */ public class TeamTest { //mybatis的配置文件--相当于创建工厂的图纸 private String resource="mybatis.xml"; @Test public void testFindAll(){ try {//1、读取mybatis的配置文件 Reader reader = Resources.getResourceAsReader(resource) ; //2、创建SqlSessionFactory对象,目的是获取sqlSession--根据图纸创建工厂 SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(reader); //3、创建可以执行SQL语句的SqlSession--工厂创建产品 SqlSession sqlSession = sqlSessionFactory.openSession(); //4、执行SQL语句 List<Team> teamList = sqlSession.selectList("com.kkb.pojo.Team.findAll"); //5、循环输出查询的结果 for (Team team : teamList) { System.out.println(team); }//6、关闭SqlSession,释放资源 sqlSession.close(); } catch (IOException e) { e.printStackTrace(); } } }
8.入门案例的增删改查
Team.xml的映射文件中添加:
8.1根据ID查询单个对象
<!--根据ID查询 parameterType="参数的类型",目前只支持一个参数 where teamId=#{id}: #{id}表示参数 id-自定义,只需要符合命名规范即可,没有实际对应意义 --> <select id="findById" parameterType="int" resultType="com.kkb.pojo.Team"> select * from team where teamId=#{id} </select>
测试类中添加如下内容:
private SqlSession sqlSession; @Test public void testFindById(){ Team team=sqlSession.selectOne("com.kkb.pojo.Team.queryById",1001); System.out.println(team); }@Before public void before() throws IOException { //1、读取mybatis的配置文件 Reader reader = Resources.getResourceAsReader(resource) ; //2、创建SqlSessionFactory对象,目的是获取sqlSession--根据图纸创建工厂 SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(reader);//3、创建可以执行SQL语句的SqlSession--工厂创建产品 sqlSession = sqlSessionFactory.openSession(); }@After public void after(){ sqlSession.close(); }
8.2增删改
在增删改的java代码运行时,需要手动提交
<!--删除一个球队 --> <delete id="del" > delete from team where teamId=#{id} </delete> <!--更新一个球队 --> <update id="update" parameterType="com.kkb.pojo.Team"> update team set teamName=#{teamName},location=#{location} where teamId=#{teamId} </update> <!--添加一个球队 parameterType="com.kkb.pojo.Team" 将对象作为参数, #{值} 值必须是实体类中的属性名称,其实就是占位符? --> <insert id="add" parameterType="com.kkb.pojo.Team" > INSERT INTO `team` (`teamName`, `location`, `createTime`) VALUES (#{teamName}, #{location}, #{createTime}) </insert>
二、Mybatis对象分析
1 Resources
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
2 SqlSessionFactoryBuilder
SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 事实上使用SqlSessionFactoryBuilder的原因
是将SqlSessionFactory这个复杂对象的创建交由Builder来执行,也就是使用了建造者设计模式。
建造者模式: 又称生成器模式,是一种对象的创建模式。 可以将一个产品的内部表象与产品的生成过程分割开来, 从而可以使一个建造过程生成具有 不同的内部表象的产品(将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示). 这样用户只需指定需要建造的类型就可 以得到具体产品,而不需要了解具体的建造过程和细节. 在建造者模式中,角色分指导者(Director)与建造者(Builder): 用户联系指导者, 指导者指挥建造者, 最后得到产品. 建造者模式可以强制实行 一种分步骤进行的建造过程.
3 SqlSessionFactory
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:
1、会开启一个事务(也就是不自动提交)。
2、将从由当前环境配置的 DataSource 实例中获取 Connection 对象。事务隔离级别将会使用驱动或数据源的默认设置。
3、预处理语句不会被复用,也不会批量处理更新。
openSession(true):创建一个有自动提交功能的
SqlSession openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
openSession():同 openSession(false)
4 SqlSession
- SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以SqlSession 对象的关闭结束。
- SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。
- SqlSession 在方法内部创建,使用完毕后关闭。
- SqlSession 类中有超过 20 个方法,我们常用的几乎都是执行语法相关的方法。
- 这些方法被用来执行定义在 SQL 映射的 XML 文件中的 SELECT、INSERT、UPDATE 和 DELETE 语句。它们都会自行解释,每一句都使用语句的 ID 属性和参数对象,参数可以是原生类型(自动装箱或包装类)、JavaBean、POJO 或 Map。
<T> T selectOne(String statement, Object parameter) <E> List<E> selectList(String statement, Object parameter) <K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey) int insert(String statement, Object parameter) int update(String statement, Object parameter) int delete(String statement, Object parameter) <!--selectOne 和 selectList 的不同仅仅是 selectOne 必须返回一个对象或 null 值。如果返回值多于一个,那么就会抛出异常。 selectMap 稍微特殊一点,因为它会将返回的对象的其中一个属性作为 key 值,将对象作为 value 值,从而将多结果集转为 Map 类型值。因为 并不是所有语句都需要参数,所以这些方法都重载成不需要参数的形式。 -->
5 Mybatis架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-epVhZish-1627200025262)(C:\Users\柳佳宇\AppData\Local\Temp\1621471223880.png)]
1、Mybatis.xml文件是mybatis框架的全局配置文件,配置了mybatis框架运行的环境等信息。 Mapper1.xml.....是SQL的映射文件,文件中配置了所有的操作数据库的sql语句,这些文件需要在全局配置文件中加载。
2、通过mybatis环境等配置信息构建SqlSessionFactroy ,相当于是产生连接池
3、由会话工厂创建SqlSession即会话(连接),操作数据库需要通过SqlSession进行的。
4、Mybatis底层自定义了Executor执行器的接口操作数据库,Executor接口有两个实现,一个基本的执行器,一个是缓存的执行器。
5、Mapped statement 也是mybatis框架一个底层的封装对象,他包装了mybatis配置信息以及sql映射信息。Mapper.xml文件中的一个SQL语 句对应一个Mapped statement对象,sql的id就是Mapped statement的id。
6、Mapped statement对SQL执行输入参数的定义,输入参数包括HashMap、基本类型、pojo,Executor通过Mapped statemen在执行SQL语句 前将输入java对象映射到sql语句中,执行完毕SQL之后,输出映射就是JDBC编码中的对preparedStatement 执行结果的定义。
三、配置日志文件
1 添加jar依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version> </dependency>
2 添加日志配置文件–在resource下添加log4j.properties配置文件
# 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
3 在mybatis配置文件中添加日志的配置
<configuration>
<!--配置日志,注意顺序:查看属性点击configuration进入查看即可-->
<settings>
<setting name="logImpl" value="LOG4J" />
</settings> ......
四、使用原有的Dao方式开发->只是为了熟悉一下,
1、创建工具类
1.1 ThreadLocal------让sqlsession线程安全的方法
ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本, 是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
1.2 工具类—创建一个连接操作的工具类
package com.kkb.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.IOException; import java.io.Reader; /*** ClassName: SessionUtil * 连接操作的工具类 * @author wanglina * @version 1.0 */ public class MybatisUtil { private static ThreadLocal<SqlSession> threadLcoal = new ThreadLocal<SqlSession>(); private static SqlSessionFactory SqlSessionFactory; /**** 加载配置文件 */ static{ try{Reader reader = Resources.getResourceAsReader("mybatis.xml"); SqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); }catch(IOException e){ e.printStackTrace(); throw new RuntimeException(e); } }/*** 获取SqlSession * @return */ public static SqlSession getSqlSession(){ //从当前线程获取 SqlSession sqlSession = threadLcoal.get(); if(sqlSession == null){ sqlSession = SqlSessionFactory.openSession(); //将sqlSession与当前线程绑定 threadLcoal.set(sqlSession); }return sqlSession; }/*** 关闭Session */ public static void closeSqlSession(){ //从当前线程获取 SqlSession sqlSession = threadLcoal.get(); if(sqlSession != null){ sqlSession.close(); threadLcoal.remove(); } } }
2、创建TeamDao接口和实现类
package com.kkb.dao; import com.kkb.pojo.Team; import java.util.List; /*** ClassName: TeamDao * 原有的dao写法 * @author wanglina * @version 1.0 */ public interface TeamDao { List<Team> queryAll(); Team queryById(Integer teamId); int add(Team team); int update(Team team); int del(Integer teamId); }
package com.kkb.dao; import com.kkb.pojo.Team; import com.kkb.utils.MybatisUtil; import org.apache.ibatis.session.SqlSession; import java.util.List; /*** ClassName: TeamDao * Team的数据访问层 * @author wanglina * @version 1.0 */ public class TeamDaoImpl implements TeamDao { /*** 查询所有球队 * @return */ public List<Team> queryAll(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); List<Team> teamList = sqlSession.selectList("com.kkb.pojo.Team.findAll"); return teamList; }/*** 根据id查询单个球队 * @param teamId * @return */ public Team queryById(int teamId){ SqlSession sqlSession = MybatisUtil.getSqlSession(); Team team=sqlSession.selectOne("com.kkb.pojo.Team.findById",teamId); return team; }/*** 添加球队 * @param team * @return */ public int add(Team team){ SqlSession sqlSession = MybatisUtil.getSqlSession(); int num = sqlSession.insert("com.kkb.pojo.Team.add", team); sqlSession.commit();//必须提交才能让增删改生效 return num; }/*** 更新球队 * @param team * @return */ public int update(Team team){ SqlSession sqlSession = MybatisUtil.getSqlSession(); int num = sqlSession.insert("com.kkb.pojo.Team.update", team); sqlSession.commit();//必须提交才能让增删改生效 return num; }/*** 根据id删除球队 * @param teamId * @return */ public int del(int teamId){ SqlSession sqlSession = MybatisUtil.getSqlSession();int num = sqlSession.insert("com.kkb.pojo.Team.del", teamId); sqlSession.commit();//必须提交才能让增删改生效 return num; } }
五、使用Mapper的接口编写Mybatis项目—重点!!!
1、什么是Mapper接口
在前面例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工作,它仅仅就是通过 SqlSession 的相关API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。
所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对DB 进行操作。这种对 Dao 的实现方式称为Mapper接口的动态代理方式。
Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。
2、实现步骤------重点!!!
2.1 编写接口TeamMapper.java
package com.kkb.mapper; import com.kkb.pojo.Team; import java.util.List; /*** ClassName: TeamMapper * Mapper接口 * @author wanglina* @version 1.0 */ public interface TeamMapper { List<Team> queryAll(); Team queryById(int teamId); int add(Team team); int update(Team team); int del(int teamId); }
创建TeamMapper.xml文件,与Team.xml内容几乎一样,只有namespace="com.kkb.mapper.TeamMapper"修改为接口的完全限定名
<?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.kkb.mapper.TeamMapper"> <!--省略内容,复制Team.xml中的内容即可--> </mapper>
在mybatis.xml配置文件中注册映射文件
<mappers>
<!--省略其他--> <mapper resource="com/kkb/mapper/TeamMapper.xml"/>
</mappers>
2.2 getMapper方法获取代理对象
只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。
package com.kkb.test; import com.kkb.dao.TeamDao; import com.kkb.dao.TeamDaoImpl; import com.kkb.mapper.TeamMapper; import com.kkb.pojo.Team; import com.kkb.utils.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.Date; import java.util.List; /*** ClassName: TeamDaoTest * TeamMapper的测试类 * @author wanglina * @version 1.0 */ public class TeamMapperTest { private SqlSession sqlSession=MybatisUtil.getSqlSession(); @Test public void test01(){ TeamMapper teamDao= sqlSession.getMapper(TeamMapper.class); //添加 Team team=new Team(); team.setTeamName("勇士"); team.setLocation("金州"); team.setCreateTime(new Date()); int num=teamDao.add(team); sqlSession.commit();//必须提交才能让增删改生效 System.out.println(num); //更新 Team team1 = teamDao.queryById(1001); team1.setTeamName("lina的球队"); num = teamDao.update(team1); sqlSession.commit();//必须提交才能让增删改生效 System.out.println(num); //删除 num=teamDao.del(1001); sqlSession.commit();//必须提交才能让增删改生效 System.out.println(num); //查询所有 List<Team> teams = teamDao.queryAll(); teams.forEach(t-> System.out.println(t)); } }
3 实现原理—看源码
六、增删改查中的细节—特殊操作
6.1 插入数据的时候获取自增的id
6.1.1 案例准备–数据库、实体类、mapper、接口
6.1.2 修改配置文件
添加GameRecordMapper.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"> <!--namespace="名称必须与映射的类的名字一致,是完全限定名"--> <mapper namespace="com.kkb.mapper.GameRecordMapper"> <!--添加一条比赛记录 --> <insert id="add" parameterType="com.kkb.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>
修改TeamMapper.xml文件中的insert节点
<!--添加一个球队 parameterType="com.kkb.pojo.Team" 将对象作为参数, #{值} 值必须是实体类中的属性名称,其实就是占位符? --> <insert id="add" parameterType="com.kkb.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`) VALUES (#{teamName}, #{location}, #{createTime}) </insert>
6.2 输入映射—输入多个参数
6.2.1 parameterType
parameterType:接口中方法参数的类型,类型必须是完全限定名或别名(稍后讲别名)。该属性非必须,因为Mybatis框架能自行判断具体传入语句的参数,默认值为未设置(unset)。
6.2.1.1—方式一
TeamMapper.xml配置文件中添加如下:
<!--多个参数:标签中不需要parameterType属性 方式1:通过下标索引的方式,还有两种方式(太难记了,可以忽略,看看演示就好啦) select * from team where teamId >=#{arg0} and teamId <=#{arg1}; 也可以,注意下表索引 细节1:mybatis3.3版本之前:可以直接写#{0} #{1} 从mybatis3.4开始:#{arg0} #{arg1}... 或者是 #{param1} #{param2}... 细节2:sql语句中不能使用小于号,使用转移符号替换;大于号没有限制,也可以使用转义符号替换> --> <select id="queryByRange1" resultType="com.kkb.pojo.Team"> select * from team where teamId >=#{param1} and teamId <=#{param2}; </select>
6.2.1.2—方式二 通过@Param注解
在方法的形参前面加入@Param(“自定义参数名称”),mapper文件中使用#{自定义参数名称}的方式传参。
TeamMapper接口添加如下内容:
List<Team> queryByRange2(@Param("min") Integer min, @Param("max") Integer max);
TeamMapper.xml配置文件中添加如下:
<!--方式2:通过注解的方式: #{}中的名称必须与接口的方法中的参数注解@Param()保持一致 select * from team where teamId >=#{param1} and teamId <= #{param2}; 不推荐,但是语法也是正确的,但是不能使用arg0,arg1...... --> <select id="queryByRange2" resultType="com.kkb.pojo.Team"> select * from team where teamId >=#{min} and teamId <= #{max}; </select>
6.2.1.3—方式三 通过map来传递多个参数
Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值
TeamMapper接口添加如下内容:
List<Team> queryByRange3(Map<String,Object> map);
TeamMapper.xml配置文件中添加如下:
<!--方式3:通过map来传递多个参数:映射文件中的参数占位符必须和map中的String类型的字段名称一样--> <select id="queryByRange3" resultType="com.kkb.pojo.Team"> select * from team where teamId >=#{min} and teamId <= #{max}; </select>
6.2.1.4—方式四 通过pojo类传递多个参数
与map传递多个参数类似,要求映射文件中的参数占位符必须和pojo类中的属性完全一致。
实体类—用于存放要输入参数的类:
TeamMapper接口添加如下内容:
List<Team> queryByCondition(QueryVO vo);//vo为参数的实体类
TeamMapper.xml配置文件中添加如下:
<!--方式4:通过pojo类传递多个参数:映射文件中的参数占位符必须和pojo类中的字段完全一致--> <select id="queryByCondition" resultType="com.kkb.pojo.Team"> select * from team where teamId>=#{min} and teamId<=#{max} and teamName like #{name} and location=#{location} </select>
6.3 #{} 和 ${}的区别–面试中喜欢出的考题!!!
6.3.1 #{}
#{}:表示一个占位符,通知Mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。这个是Mybatis 中的首选做法,安全迅速。
6.3.1 ${}
${}:表示字符串原样替换,通知Mybatis 使用$包含的“字符串”替换所在位置。使用 Statement或者PreparedStatement 把 sql 语句和${}的内容连接起来。一般用在替换表名,
列名,不同列排序等操作。
6.4 输出映射
6.4.1 resultType
resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。如果返回的是集合,设置的是集合元素的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。
6.4.1.1 输出简单类型
TeamMapper接口添加如下内容:
int getCount();
TeamMapper.xml配置文件中添加如下:
<!-- 只有返回的结果是单行的时候,返回值类型才可以指定为基本类型 如果是单行多列,也取不到后面的列的值; 如果返回多行会报异常:TooManyResultsException--> <select id="getCount" resultType="java.lang.Integer"> select count(teamId) from team </select>
6.4.1.2 输出pojo类型
TeamMapper.xml配置文件中添加如下:
<!--接口方法返回是集合类型,但是映射文件中的resultType需要指定集合中的类型,不是集合本身。--> <select id="queryAll" resultType="com.kkb.pojo.Team"> select * from team; </select>
6.4.1.3 输出Map类型
当我们只需要查询表中几列数据的时候可以将sql的查询结果作为Map的key和value。一般使用的是Map<Object,Object>.
Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录会抛出TooManyResultsException异常。
如果有多行,使用List<Map<Object,Object>.
TeamMapper接口添加如下内容:
Map<Object,Object> queryTwoColumn(int teamId); List<Map<Object,Object>> queryTwoColumnList();
TeamMapper.xml配置文件中添加如下:
<select id="queryTwoColumn" resultType="java.util.HashMap"> select teamName,location from team where teamId=#{id} </select> <select id="queryTwoColumnList" resultType="java.util.HashMap"> select teamName,location from team </select>
6.4.2 resultMap
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。
常用在列名和 java 对象属性名不一样的情况。
使用方式:
1.先定义 resultMap,指定列名和属性的对应关系。
2.在中把resultType替换为resultMap
TeamMapper.xml映射文件添加:
<!--resultMap 和resultType不能同时出现 resultMap:是引用的自己创建resultMap的id--> <select id="queryAll2" resultMap="baseResultMap"> select * from team; </select><!--创建resultMap:相当于自己编写表中的列与实体类中的属性的映射 id:resultMap的名称,要求唯一 type:期待要映射为java的类型 --> <resultMap id="baseResultMap" type="com.kkb.pojo.Team"> <!--一般主键列用id,其余列用result column:表示数据库表中的列名,不区分大小写 property:表示实体类中的对应的属性名,区分大小写 javaType:实体类中的对应的属性的类型,可以省略,mybatis会自己推断 jdbcType="数据库中的类型column的类型" 一般省略 --> <id column="teamId" property="teamId" javaType="java.lang.Integer" ></id> <result column="teamName" property="teamName" javaType="java.lang.String"></result> <result column="location" property="location" javaType="java.lang.String"></result> <result column="createTime" property="createTime" javaType="java.util.Date"></result> </resultMap>
6.4.3 数据库表中列与实体类属性不一致的处理方式
6.4.3.1 使用列别名和resultType
映射文件UsersMapper.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.kkb.mapper.UsersMapper"> <!--方式1:resultType中的实体类的属性作为查询语句中的别名,让别名和属性保持一致--> <select id="queryByID" resultType="com.kkb.pojo.Users"> select user_id as userId,user_name as userName,user_age as userAge from users where user_id=#{id}; </select> </mapper>
6.4.3.2 使用resultMap
映射文件UsersMapper.xml添加如下内容:
<!--方式2:通过resultMap自行映射--> <select id="queryByID2" resultMap="baseMap"> select * from users where user_id=#{id}; </select> <resultMap id="baseMap" type="com.kkb.pojo.Users"> <id column="user_id" property="userId"/> <result column="user_name" property="userName"/> <result column="user_age" property="userAge"/> </resultMap>
七、Mybatis的全局配置文件
案例中使用的 mybatis.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">
7.1 配置的内容—顺序很重要
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
configuration(配置)
properties--属性:加载外部的配置文件,例如加载数据库的连接信息
Settings--全局配置参数:例如日志配置
typeAliases--类型别名
typeHandlers----类型处理器
objectFactory-----对象工厂
Plugins------插件:例如分页插件
Environments----环境集合属性对象
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
Mappers---映射器:注册映射文件用
7.2 属性(properties)
- 属性可以在外部进行配置,并可以进行动态替换。我们既可以在 properties 元素的子元素中设置(例如DataSource节点中的properties节点),也可以在 Java 属性文件中配置这些属性。
- 数据源中有连接数据库的四个参数数据,我们一般都是放在专门的属性文件中,mybatis的全局配置文件直接从属性文件中读取数据即可。
7.2.1、在 resources 目录创建 jdbc.properties 文件,文件名称可以自定义。
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
jdbc.username=root
jdbc.password=root
7.2.2、mybatis的全局配置文件引入属性文件
<properties resource="jdbc.properties"/>
7.2.3、使用属性文件中的值
<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>
7.3 设置 settings
MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为.例如我们配置的日志就是应用之一。其余内容参考http://xn–mybatis-m43kk2dt42i5bzbkmwea1425byor/
<!--配置日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
7.4 类型别名 typeAliases
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
7.4.1 Mybatis中已经支持的别名
别名 | 映射的类型 |
---|---|
_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 |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
7.4.2 自定义别名—很重要
<!--自定义类型别名-->
<typeAliases>
<!--对单个的实体类定义别名-->
<typeAlias type="com.kkb.pojo.Team" alias="Team"/>
<!--推荐写法:批量定义别名:扫描指定包下的所有类,同时别名定义为类名,别名的首字母大小写都可以-->
<package name="com.kkb.pojo"/> </typeAliases>
7.5 映射器 Mappers
配置有多种方式:
7.5.1、 使用相对于类路径的资源引用
语法:<mapper resource=""/>
使用相对于类路径的资源,从 classpath 路径查找文件 例如:
<mapper resource="com/kkb/mapper/TeamMapper.xml" />
7.5.2、使用映射器接口实现类的完全限定类名
语法:<mapper class=""/>
使用的mapper接口的完全限定名
要求:接口和映射文件同包同名
例如<mapper class="com.kkb.mapper.GameRecordMapper"/>
7.5.3、将包内的映射器接口实现全部注册为映射器—推荐
语法:<package name=""/>
指定包下的所有Mapper接口
如:<package name="com.kkb.mapper"/>
注意:此种方法要求 Mapper接口名称和 mapper 映射文件名称相同,且在同一个目录中。
7.6 dataSource标签
Mybatis 中访问数据库支持连接池技术,而且是采用的自己的连接池技术。在 Mybatis 的 mybatis.xml配置文件中,通过来实现 Mybatis 中连接池的配置。MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource。
Mybatis 的数据源分为三类:
UNPOOLED: 不使用连接池的数据源
POOLED:使用连接池的数据源
JNDI:使用JNDI实现的数据源
前两个数据源都实现javax.sql.DataSource接口
7.7 事务
7.7.1、默认是需要手动提交事务的
Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection对象的 commit(), rollback() .Connection 对象的 setAutoCommit()方法来设置事务提交方式的。自动提交和手工提交.
该标签用于指定 MyBatis所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。
JDBC:使用JDBC的事务管理机制,通过Connection对象的 commit()方法提交,通过rollback()方法 回滚。默认情况下,mybatis将自动提交功能关闭了,改为了手动提交,观察
日志可以看出,所以我们在程序中都需要自己提交事务或者回滚事务。
7.7.2、自动提交事务—不推荐
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cNkOyCvl-1627200025263)(C:\Users\柳佳宇\AppData\Local\Temp\1621501528535.png)]
SqlSessionFactory的openSession方法由重载,可以设置自动提交的方式。
如果sqlSession = SqlSessionFactory.openSession(true);参数设置为true,再次执行增删改的时候就不需要执行session.commit()方法,事务会自动提交。
9、Mybatis中的关系映射
9.1 对一关系的映射----共有三种方法
9.1.1 实体类
public class Player {
private Integer playerId;
private String playerName;
private Integer playerNum;
private Integer teamId;
//多对一的体现:多方持有一方的对象 要有get方法
private Team team1;//关联对象--多个球员可以属于同一个球队;
//省略set get 和toString方法
9.1.2 mapper接口
以我们在程序中都需要自己提交事务或者回滚事务。
7.7.2、自动提交事务—不推荐
[外链图片转存中…(img-cNkOyCvl-1627200025263)]
SqlSessionFactory的openSession方法由重载,可以设置自动提交的方式。
如果sqlSession = SqlSessionFactory.openSession(true);参数设置为true,再次执行增删改的时候就不需要执行session.commit()方法,事务会自动提交。
9、Mybatis中的关系映射
9.1 对一关系的映射----共有三种方法
9.1.1 实体类
public class Player {
private Integer playerId;
private String playerName;
private Integer playerNum;
private Integer teamId;
//多对一的体现:多方持有一方的对象 要有get方法
private Team team1;//关联对象--多个球员可以属于同一个球队;
//省略set get 和toString方法