MyBatis笔记
代码模板
代码模板/pom.xml
代码模板/jdbc.properties
代码模板/SQLMapConfig.xml
... ...
讲解
基本MyBatis的5个步骤
标签释义
代理接口开发
typeHandler标签
plugin/pagehelper
多表操作
表间关系
一对一表间关系
<association><javaType>
<collection><ofType>一对多表间关系
多对多查询
[插播]junit单元测试
注解开发
介绍
注解开发的多表操作
延期
注意\报错
注意
报错
未解决
视频梗概
END
- - - - - - 以下为正文 - - - - - -
MyBatis笔记
第1刷,南湖立交2021.12,课程来源:B站up/黑马
代码模板
代码模板/pom.xml
```
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!--junit 单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.0.3</version>
<scope>test</scope>
</dependency>
<!-- 添加slf4j日志api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<!-- 添加logback-classic依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 添加logback-core依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
</dependencies>
```
代码模板/jdbc.properties
```
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db03
jdbc.username=root
jdbc.password=1111
```
代码模板/SQLMapConfig.xml
```
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis//DTD Config 3.0//EN" "http://mybatis/dtd/mybatis-3-config.dtd">
<configuration>
<!--通过properties标签加载外部properties文件-->
<properties resource="jdbc.properties"></properties>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.it.domain.User" alias="user"></typeAlias>
<typeAlias type="com.it.domain.Order" alias="order"></typeAlias>
</typeAliases>
<!--配置分页助手插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"></property>
</plugin>
</plugins>
<!--数据源环境-->
<environments default="developement">
<environment id="developement">
<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>
</environments>
<!--加载映射文件-->
<mappers>
<!--xml配置开发用mapper-->
<mapper resource="com/it/mapper/UserMapper.xml"></mapper>
<!--注解开发用package-->
<package namespace="com/it/mapper"/>
</mappers>
</configuration>
```
代码模板/XxMapper.xml
```
<!-- 定义与 SQL 映射文件同名的 Mapper 接口,并且将 Mapper 接口和 SQL 映射文件放置在同一目录下。-->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis//DTD Mapper 3.0//EN" "http://mybatis/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.it.mapper.OrderMapper">
<resultMap id="orderMap" type="order">
<id column="oid" property="id"/>
<!-- 单行数据封装方案:<result>-->
<result column="total" property="total"/>
<!-- <result column="username" property="user.username"/>-->
<!-- <result column="password" property="user.password"/>-->
<!-- 多行数据封装方案:<association>-->
<association property="user" javaType="user">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
</association>
</resultMap>
<select id="findallorderuser" parameterType="order" resultMap="orderMap">
select *,ordert.id oid from ordert,user where uid=user.id
</select>
</mapper>
```
代码模板/Xx.java
```
// //属性写在实体类里,方法写在接口里
//一对多\多对多查询的情况下,其他表的数据封装为实体类中的一个对象或以对象为元素的List集合
public class User {
public int id;
public String username;
public String password;
Order order=new Order();//单行查询返回单对象,例如findById
List<Order> orderList;//多行查询返回多对象,例如findAll
//实际需要但此处省略getter,setter,toString
}
```
代码模板/XxMapper.java
```
public interface UserMapper {
//属性写在实体类里,方法写在接口里
//数据->typeAlisas别名
//insert->save()
//select->find()
//数据表的列->字段
//实体类的变量->属性
public void save();//insert\update\delete无需返回数据,故用void
public User findById();//select返回单行数据封装为单个对象
public List<User> findall();//select返回多行数据封装为多个对象
}
```
代码模板/MyBatisDemo.java
```
//无注解入门版
private static void test1() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper orderMapper=sqlSession.getMapper(OrderMapper.class);
Order order=new Order();
order.setId(1);
List<Order> orderList = orderMapper.findallorderuser(order);
for (Order orders : orderList) {
System.out.println(orders);
}
sqlSession.close();
}
//注解版
public class AnnoDemo {
private UserMapper mapper;
@BeforeEach
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
}
@Test
void test1save()throws IOException{...}
//C,create==insert==save,需要参数,无返回值
//R,retrieve==select==find,根据给定条件查询需要参数,无条件查询不需要参数..返回单行数据封装为单个对象Xx,返回多行数据封装为多个对象List<Xx>
//U,update,需要参数,无返回值
//D,delete,需要参数,无返回值
```
代码模板/<select><if>
```
<select id="findByCondition" parameterType="user" resultType="user">
select * from user
<where>
<if test="id!=0">
and id=#{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
<if test="password!=null">
and password=#{password}
</if>
</where>
</select>
```
代码模板/<sql><include>
<sql id="selectUser">select * from user</sql>
<select id="findByCondition" parameterType="user" resultType="user">
<include refid="selectUser"></include>
</select>
代码模板/findAll()
// 查询所有数据 - basic
//
interface BrandMapper{
List<Brand> selectAll();
}
//
<select id="selectAll" resultType="brand">
select * from tb_brand;
</select>select>
//
<mapper namespace="com.itheima.mapper.BrandMapper">
<select id="selectAll" resultType="brand">
select * from tb_brand;
</select>
</mapper>
//
BrandMapper brandMapper=sqlSession.getMapper(BrandMapper.class);
List<Brand> brands=brandMapper.selectAll();
代码模板/<resultMap>
<resultMap id="brandResultMap" type="brand">
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
应用场景:查询部分字段
只查询部分字段而不是所有字段,就可以使用resultMap的方式.
resultMap定义字段和属性的映射关系.
字段名==属性名的,不需要定义出来.
sql语句使用resultMap时,<select>标签内引入相关resultMap,如下
<select id="selectAll" resultMap="brandResultMap">
select * from tb_brand;
</select>
代码模板/<if>
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</if>
</select>
代码模板/<foreach >
原始语句:select * from - where - in(-,-);//可称为"多选查询",同类的还有"单项查询""范围查询"
练习中的方法:findByIds
顺序 | 文件 | 格式 | 描述 |
1 | UserMapper | .java | public List findByIds(List ids); |
2 | UserMapper | .xml | <foreach...>...</> |
3 | DynamicSqlDemo | .java | |
<whrere>
<foreach collection open close item separator></foreach>
<foreach collection="" open="" close="" item="" separator=""></foreach>
<foreach collection="list" open="id in(" close="(" item="id" separator=",">
#id
</foreach>
</where>
代码模板/plugin/pagehelper
<plugins>
<pligin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</pligin>
</plugins>
代码模板/choose
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null"><!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName != '' "><!--相当于case-->
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''"><!--相当于case-->
brand_name like #{brandName}
</when>
</choose>
</where>
</select>
代码模板/create table
CREATE TABLE ordert
(
id INT(11) PRIMARY KEY,
uid INT(11),
CONSTRAINT fk_order_user FOREIGN KEY(uid) REFERENCES user(id));
-- 表名不能用order,order是mysql的关键字
代码模板/<association javaType>
- <associate>标签
作用:用于匹配类中包含引用数据的column-property匹配,例如:
class Order{
...
private User user;
...
}
讲解
[课程目标]使用MyBatis完成对数据的查增改删.
[各部分说明]一共2部分,1部分有10节,1.1-1.10,即查增改删,2部分仅1节,即注解实现CRUD.
[1部分说明]环境准备,查所有,查一行,多条件查,单条件查,加数据,改数据,删数据,批量删,参数传递.
[知识点]MyBatis基本步骤,MyBatisX,查询基本步骤,增基本步骤,改基本步骤,删基本步骤
[代码]xml代码,接口代码,sql语句,测试类代码
[!]JDBC自动提交事务,但是MyBatis默认不提交事务.
[!]MyBatis的CRUD有2种方式:xml配置\注解开发.xml配置较全面,注解开发用于简单CRUD比xml配置更简单,用于复杂的CRUD会需要非常复杂的代码.
基本MyBatis的5个步骤
[视频]黑马SSM
e149,6:30
开发环境:相关的实体类\测试类,在pom.xml添加依赖,包括但不限于mysql\jdbc\mybatis\junit\log4j...依赖
编写jdbc.properties
编写SQLMapConfig.xml
编写XxMapper.xml
编写XxMapper.java(这是interface)
(黑马原文)MyBatis开发步骤-1-添加MyBatis的坐标,-2-创建user数据表,-3-编写user实体类,-4-编写映射文件UserMapper.xml,-5-编写核心文件SQLMapConfig.xml,-6-编写测试类
标签释义
标签 | 别名/描述 |
namespace | 是当前xml文件的命名空间,namespace+"."+id组成访问的唯一标识,,, |
<select id> | 有findAll\update\delete等,,,< |
<select resultType> | 一般写相应的类的全限定类名,是封装mysql执行结果的目的地,,, |
sqlMapConfig.xml | 核心文件 |
<mappers><mapper></mappers> | 映射器,适用于xml开发,引入XXMapper.xml到SQLMapperConfig.xml |
<mappers><package></mappers> | 映射器,适用于注解开发,引入XXMapper.java到SQLMapperConfig.xml |
<properties> | 属性,引入jdbc.properties |
settings | 设置 |
<typeAliases> | 类型别名 |
<typeHandlesrs> | 类型处理器 例如:[需求]支持在java程序中输入一个毫秒值作为生日,存储到数据库后可转换为年月日日期格式,故新建列时选择数据类型为bigint |
<plugins> | 插件,例如pageHlper |
<environments> | 环境,内含-1-事务管理器-2-数据源. -1-transactionManager事务管理器,作用是提交和回滚,有2种:JDBC\MANAGED,这里使用JDBC -2-dataSource,作用是打开和关闭连接,有3种:UNPOOLED\POLLED\JNDI,这里使用POOLED |
transactionManager | 事务管理器 |
dataSource | 数据源 |
databaseIdProvider | 数据库厂商标识 |
提交事务 | 方案A:系统自动提交事务 openSession(true); openSession();sqlSessionmit(); |
操作事务 | void commit(); |
id | 完成主键字段的映射 |
column | 表的列名 |
property | 实体类的属性名 |
result | 完成一般字段的映射 |
resultMap | 定义 字段 和 属性 的映射关系 |
#{},${} | 属性占位符,要求 属性名 或map集合的键名和 参数占位符名称 一致 |
parameterType | 参数类型 |
javaType | 实体类类型 |
if,choose,trim,foreach,where | 动态sql |
useGeneratedKeys,keyProperty | 主键返回 |
@select,@create,@update,@delete | 注解,使用了注解,就不需要再映射配置文件中书写对应的 statement,但不适合用于较复杂的CRUD |
<sql><include> | sql语句抽取 |
<select> | 查 |
<insert> | 增 |
<update> | 改 |
<delete> | 删 |
<where> | 条件 |
<if> | 动态sql/多条件 |
<foreach> | 动态sql/单选条件 |
<sql> | sql语句抽取 |
代理接口开发
[描述]代理开发方式介绍
采用MyBatis的代理开发方式实现dao层的开发,这种方式是我们后面进入企业的主流.mapper接口开发方式只需要程序员编写mapper接口(相当于dao接口),由MyBatis框架根据接口定义创建链接的动态代理对象,代理对象的方法体同上边dao接口实现类方法.
mapper进口开发需要遵循以下规范
mapper.xml文件中的namespace与mapper接口的全限定名相同.
mapper接口方法名和mapper.
xml中定义的每个statement的id相同.mapper进口方法的输入参数类型和mapper.
xml中定义的每个sql的parameterType的类型相同.
mapper接口方法名的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同.
sqlSession.xx();代理接口开发实现的是这一步,例如sqlSession.getMapper();
typeHandler标签
无论是MyBatis在Pstmt预处理语句中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成Java类型.例如下表
类型处理器 | Java类型 | JDBC类型 |
BooleanTypeHandler | java.lang.Boolean | boolean |
ByteTypeHandler | java.lang.Byte | numeric\Byte |
ShortTypeHandler | java.lang.short | numeric\short\int |
IntegerTypeHandler | java.lang.int | numeric\integer |
LongTypeHandler | java.lang.long | numeric\long\integer |
你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型.具体做法为:实现org.apache.ibatis.type.TypeHandler接口,或继承一个很便利的类org.apache.ibatis.type.BaseTypeHandler,然后可以选择性地将它映射到一个JDBC类型.
例如
[需求]
一个Java中的date数据类型,现在要存储到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成Java的date数据类型,即Java的date与数据库的varchar毫秒值之间的转换.
[开发步骤]
-1-定义转换类继承类BaseTypeHandler
-2-覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时mysql的字符串类型转换为java的Type类型的方法
-3-在MyBatis核心配置文件中进行注册
-4-测试转换是否正确
[关键词]
TypeHandler
BaseTypeHandler
setNonNullParameter
getNullableResult
[步骤]
- 建包:com.it.handler
- 新建类:DateTypeHandler.java
-
- DateTypeHandler继承BaseTypeHandler
- 重写4个方法:setNonNullParameter()等
plugin/pagehelper
[需求]
查询一个表中的所有数据,以分页效果显示
[开发步骤]
导入通用pagehelper的坐标
在MyBatis核心配置文件中配置pagehelper插件
测试分页数据获取
多表操作
表间关系
在mysql中,表间关系以外键约束体现.
在Java中,表间关系以类中引用体现.
- 主表(父表):对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表。
- 从表(子表):对于两个具有关联关系的表而言,相关联字段中外键所在的表就是从表。
-- mysql
CREATE TABLE tb_emp6(
id INT(11) PRIMARY KEY,
name VARCHAR(25),
deptId INT(11),
FOREIGN KEY(deptId) REFERENCES tb_dept1(id)
);
//外键约束的环境:A表的2个字段:id,bid,B表的1个字段:id.
//外键约束的逻辑:为bid添加外键约束,链接B表的id
//java
pubilc class User{
Order order=new Order;
}
一对一表间关系
[需求]
- 为User,Order创建一对一表间关系
[开发步骤]
- 在com.it.domain包中,创建User,Order实体类
- 在User实体类中创建Order的对象,这就是引用数据类型.
- 创建OrderMapper.xml,UserMapper.xml
<association><javaType>
同时查询2个表
SELECT * FROM t1 t,t2 tt WHERE t.c1=tt.c1;
e181
1.查询order表
2.查询order,user表
3.给2个id分别定义别名并查询order,user表
4.运行java程序并查看封装结果:封装失败
5.定义resultMap并配置column-property映射关系
6.运行程序,封装成功
[小结]
多表查询的重点就在于需要手动配置resultMap映射关系,否则程序无法自动封装查询结果并发送给java程序.
[实际练习步骤]
1.准备MySQL环境,编写以下文件
- user表
- order表
- uid外键约束
2.准备java开发环境,编写以下文件
- sqlMapConfig.xml
- UserMapper.xml
- OrderMapper.xml
- User.java
- Order.java
- UserMapper.java
- OrderMapper.java
- MultiTableSelectDemo.java
3.运行程序
*
文件 | 列名/属性名 | 列名/属性名 | 列名/属性名 |
user.table | id | username | password |
User.java | id | username | password |
文件 | 列名/属性名 | 列名/属性名 | 列名/属性名 |
order.table | id | total | uid |
Order.java | id | total | uid |
<collection><ofType>一对多表间关系
**要点**
一对多的查询,使用集合把”多”的那个表封起来,成为”一”的那个表的一个属性.在java程序中封到:属性,在xml配置中封到:<resultMap><collection></collection></resultMap>
```
//
<collection property="jihemy" ofType="ypsumy">
<id column="bxmy" property="vuxymy"></id>
<result column="bxmy" property="vuxymy"></result>
<result column="bxmy" property="vuxymy"></result>
</collection>
//
<collection property="orderList" ofType="order">
<id column="oid" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="total" property="total"></result>
</collection>
```
- e183
[模型]
user表,order表,1个user对应x个order
多对多查询
**要点**
-- table:u,r,ur
SELECT * FROM
user u,
sys_user_role ur,
sys_role r
WHERE
u.id=ur.userId AND
ur.roleId=r.id
//
<typeAlias type="com.it.domain.Role" alias="role"></typeAlias>
<resultMap id=”userRoleMap” type=”user”>
</resultMap>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
SELECT * FROM USER u,sys_user_role ur,sys_role r WHERE u.id=ur.userId AND ur.roleId=r.id
</select>
//
<mapper>
<resultMap>
<collection property="jihemy" ofType="ypsumy">
<id column="lxmy" property="vuxymy">
<result column="lxmy" property="vuxymy">
</collection>
//
public List<User> findAllUserOrder();
//
public Order order;
public List<Order> orderList;
//
public class Role {
int id;
String rolename;
String roleDesc;
}
[需求]
查询1个user对应的所有order
[开发步骤]
> 准备环境
> > sql环境
> > > user表(包含外键oid),order表,role表,并新增数据(1个user对应x个order)
> > java环境
> > > module:SingleMultiTable
> > > sqlMapConfig.xml
> > > UserMapper.xml
> > > ...
> > 写List<Order>属性,写getter setter,写<collection>标签
**<collection>标签的代码**
```
<mapper>
<resultMap>
<collection property="jihemy" ofType="ypsumy">
<id column="lxmy" property="vuxymy">
<result column="lxmy" property="vuxymy">
</collection>
//
public Order order;
public List<Order> orderList;
//练习环境:user表,role表,userrole第三方表(包含2个外键:ur_u,ur_r)
```
[阅读理解]
例如在淘宝系统中,一个user可以具有多个role,一个role可以被多个user使用.淘宝可以根据role做出用户画像\精准推荐商品.
查user的role,不需要写role的resultMap或其他xml配置,都写在user的xml配置里
???外键约束是必要的吗?练习中没有建立外键约束,程序运行没有问题
-- 添加外键约束
#ALTER TABLE 主表名 ADD FOREIGN KEY 外键名(主表字段名) REFERENCES 从表名(从表字段名);
ALTER TABLE userrole ADD FOREIGN KEY fk_role(rid) REFERENCES role(roleid);
3个表建好了,外键加好了,如何实现3个表的关联?
[插播]junit单元测试
up主@free_coder
junit5相比junit4有较大改变,推荐使用5
[基本款代码]
[断言]
assertion,给定条件,运行结果,运行效果
描述:系统根据给定条件判断运行结果,并返回运行效果.
断言有很多预设的判断方式,例如值是否相等,数组是否相等,是否空值,是否为true
[断言代码]
@BeforeEach
在运行类中所有方法前运行
@AfterEach
在运行类中所有方法后运行
@BeforeAll
运行多个方法时,@BeforeAll将第一个被运行且只运行一次.@BeforeAll方法必须是static的,
格式:@BeforeAll static xxx xxx(){...}
@Service\@SpringBootTest
举例讲解:在service层的类A中创建一个方法funA,简单粗暴的测试,是在测试类创建类A的对象a,使用a调用funA.这样测试的弊端是,也许funA依赖于多个对象,运行它需要多个对象,在复杂的项目中,做一个这样的测试也会很复杂.
使用@SpringBootTest进行测试,Spring将提供测试所需的上下文.
暂时练不了这个,因为没有练会Spring
@MockBean
描述:用于模拟运行一些不方便实际运行的操作,例如操作数据库
mock注解需要配合when条件一起使用,when条件列出给定条件和给定结果.运行结束后系统将给出when条件下运行的结果.
如果不加when条件,mock将默认基本数据类型为0,false,null等,例如return a+b;将返回结果0;
@SpyBean
和@MockBean有异曲同工之处,推荐使用@SpyBean
```
//基本款
public class Test1{
@Test
void fun1(){
System.out.println(123);
}
}
//123
//assertion
@Test
void fun1(){
int res=1+1;
Assertion.assertEquals(2,res);
System.out.println(123);
}
//@BeforeAll
//@BeforeEach
//@AfterEach
//@Servic
@Service
int add(int a,int b){
return a+b;
}
//@SpringBootTest
@SpringBootTest
public class Test3{
@Autowired
Svc1 svc1;
@Test
void t1(){
int res=svc.add(1,2);
Assertions.assertEquals(2,res);
}
//@MockBean
class Svc1{
int add(int a,int b){
return a+b;
}
int cut(int a,int b){
return a-b;
}
}
//
@MockBean
@MockBean
Svc1 svc1;
@Test
void t1(){
when(svc.add(1,1))thenReturn(3);
int res=svc1.add(1,1);
int res2=svc1.cut(2,1)
Assertions.assertEquals(2,res);
}
```
注解开发
e186介绍
这几年来注解开发越来越流行,MyBatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了.
[常用的注解]
- @Insert:新增
- @Update:修改更新
- @Delete:删除
- @Select:查询
- @Result:结果集封装
- @Results:封装多个结果集
- @One:一对一结果集封装
- @Many:一对多结果集封装
e187准备环境
project: mySpringB
module: FAnno
UserMapper.xml:预先写好CRUD的方法
使用@before\@test进行CRUD操作
(进行此操作前应已掌握junit)
e188,以xml实现的CRUD,改成以注解实现CRUD
介绍
xml文件的2个作用:承载sql语句\映射关系...xml文件改为注解的2个操作维度:sql语句\映射关系...其中,注解体现在测试类中,映射关系体现在核心文件sqlMapConfig的映射关系中...
完成之后,不再需要UserMapper.xml文件了
#xml开发注解开发对照表
xml | 注解 |
UserMapper.java UserMapper.xml | UserMapper.java |
<insert> | #Insert |
<sql> | (“”) |
<resultMap> | @results@result |
[格式]
-1-接口
interface Xxx{
@Xxx(“sql”)
void fun(){...}
}
//sql语句原本写在xml文件里,现在写到接口中-注解后-方法前,注意加双引号.
//xml里的<insert>标签,写为@Insert(“insert...”),UserMapper.xml可删掉.
-2-核心文件
加载映射文件改为加载映射关系
<mapper>标签改为<package>标签,如下
```
<mappers>
<!--<mapper>...</mapper>-->
<package name=”...”/>
</mappers>
注解开发的多表操作
MyBatis的注解实现复杂映射开发
实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,使用注解开发后,我们可以使用@Results,@Result,@One,@Many注解组合完成复杂关系的配置
- @Results
代替的是<resultMap>标签,该注解可以使用单个@Result注解,也可以使用@Result集合.
格式1: @Results({@Result(),@Result()}),格式2:@Result(@Result())|
- @Result
代替了<id>标签和<result>标签.在@Result中,
column->数据表字段名,
property->需要装配的属性名,
one->需要使用的@one注解(@Result(one=@one)())),
many->需要使用的@many注解(@Result(many=@many)()))
延期
延期学习MyBatis注解开发
注意\报错
注意
连接数据库的4个基本信息:全限定类名\url\username\password
一条数据库数据对应一个对象,同时也是一个集合元素
内行写法:写到一半注意提示,按enter补全,这么写可以少敲键盘并且导包
selectList的参数,就是xml文件中的name+id,,,xml文件中的name加上id就是sqlSession.selectList的参数
idea复制模块
- 新建模块
- 打开电脑磁盘,将旧模块的文件复制到新模块的目录中,不复制pom
- 完成
查询结果以自定义别名显示
SELECT *,id orderid FROM ordert;
//查询结果中,id将分别以id,orderid为列名显示2列
//java中的别名显示查询如下
<resultMap...>
<id column="oid" property="id"/>
...
</resultMap>
<select...>
select *,ordert.id oid from ordert,user where uid=user.id
</select>
- getResourceAsStream报红
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");//getResourceAsStream报红
InputStream inputStream=Resources.class.getResourceAsStream("sqlMapConfig.xml");//中间加上.class就不红了
下载的B站视频有音频画面不匹配的问题,优先使用浏览器看视频.
报错
1.
[已解决]Resources没有getResourceAsStream(resource ...)方法???
全部代码都按文档的去写,导包完毕\抛出异常完毕的话,是不爆红的!
2.
[已解决]mapper namespace=test的test爆红了???
解决方案A:等文档看完后看视频中的操作,
解决方案B(有效):设置 SQL 映射文件的 namespace 属性为 Mapper 接口全限定名
3.
[已解决]dos窗口输入mysql -uroot -p1111 -h127.0.0.1 -p3306不报错,再输入show databases就报错
解决: 按以下输入即可
mysql -uroot -p
1111
show databases;
4.
result type
解决方案A[有效]:使用全限定类名给result type赋值
5.
- Could not find resource com/xxx/xxxMapper.xml
运行MybatisBrandTest,报错内容很多,抛出PersistenceException异常
方案A:CSDN@向上的青春:执行maven的clean\compile,执行idea的invalidate,重启idea,重新运行,出现相同报错
方案B:参考其他CSDN答主的答案,没有找到
方案C:观察黑马的相关视频,没有涉及
方案D:暂时略过
方案E:对比下载的黑马的代码, 找出代码中存在的不同
方案F-无效:代码修改如下
原件:
\InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
修改后:
\InputStream inputStream = Resources.getResourceAsStream("SQLMapConfig.xml");//改了参数
方案G:给了3个方案,说是哪个都可以,实际全都无效
链接
方案H:@骆,-1-查看报错信息,-2-查看每个相关文件(
- pom.xml
- mybatis-config.xml
- sqlMapConfig.xml
- BrandMapper.xml
- Brand.java
- BrandMapper.java
- BrandMapperTest.test)
2个报错根源:-1-mybatis-config.xml写入数据库名,运行时间标准,-2-包名,要用斜线不要用点
原文(错误)
<property name="url" value="jdbc:mysql://mybatis?useSSL=false"/>
更正为
<property name="url" value="jdbc:mysql://localhost:3306/db03?serverTimezone=GMT"/>
//
原文(错误)
<mapper resource="com.it.mapper.BrandMapper.xml"/>
更正为
<mapper resource="com/it/mapper/BrandMapper.xml"/>
- idea没有连接数据库(应该是,因为没记得操作过),但没有文档中说的database窗口
有可能操作过,只是自己忘了,或者是刚安装时别人帮忙配置idea时操作过
解决方案:在mybatis-config.xml中配置
- 提示result type not match for select id,如下
Figure 8: image-20211221143826361
- Mapped Statements collection does not contain value for BrandMapper.save
原代码(错误)
\sqlSession.insert("BrandMapper.save",brand);//namespace+id
更正为
\sqlSession.insert("com.it.mapper.BrandMapper.save",brand);//namespace+id
namespace要全限定名,加上包名
- return userList
视频里这么写没事,自己写会报错-编译时报错
- Type interface com.it.mapper.UserMapper is not known to the MapperRegistry.
当前课程:练习动态SQL,<select id="findByCondition">
案发现场:测试类DynamicSqlDemo.java
报错信息:error was found in mapping #{}. Check syntax #{property|(expression), var1=value1, var2=value2, ...} ==说明出错的位置是映射文件
方案A,对比原代码,去掉不一致之处.==无效,且原代码没有findByCondition,只有FindByIds
方案B,检查以下文件,发现不当之处就更正并试运行
序号 | 文件 | 格式 | 修改 |
1 | jdbc | .properties | - 新增此文件 |
2 | sqlMapConfig | .xml | - |
3 | mybatis-config | .xml | - 删除此文件?因为原版资料中没有此文件 |
4 | UserMapper | .xml | - |
5 | User | .java | - |
6 | UserMapper | .java | - |
7 | DynamicSqlDemo | .java | - |
方案C,找mybatis入门文档来看,以便发现问题
至少确定一下mybatis-config.xml是不是必要的
==调试记录==
<property name="driver" value="com.mysql.jdbc.Driver"/>改为:
<property name="driver" value="${jdbc.driver}"/>
用原版的sqlmapconfig.xml替换自己的,exitcode 0!!!
==复盘==
对比两版sqlmapconfig.xml,对比结果:错误版多两行:
<typeAlias type="com.it.mapper.Brand" alias="brand">
<mapper resource="com/it/mapper/BrandMapper.xml">
测试1
成功版:\InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
未知版:\InputStream inputStream = Resources.getResourceAsStream("xx.xml");报错:error was found in mapping #{}. Check syntax #{property|(expression), var1=value1, var2=value2, ...}
测试2
注释掉错误版中多的两行,运行结果:成功
结论
错误版导致运行失败,原因在于多了两行
<typeAlias type="com.it.mapper.Brand" alias="brand"></typeAlias><mapper resource="com/it/mapper/BrandMapper.xml"></mapper>
- new Date()无法转换为int
有样学样这么写,系统提示编译时异常如上.反复来几次,又不报错了...
- Could not find resource sqlMapConfig.xml
当前课程:typeHandler
案发现场:项目/模块/运行类->MySpringB/config/DateTypeHandler
报错信息:Could not find resource sqlMapConfig.xml
复盘:回忆下解决方案,仔细排查,最终解决
- Column 'username' cannot be null
同一位置的报错,背景描述:(TypeHandlerDemo.java)user.setUsername("DANIEL");//也就是说,有给username赋值,但报错说username不能为空
发现第一个问题:
看视频,找不同.发现不同:视频的测试类里有setBirthday(new Date());我的没有,我的写了会报红.再看原代码的User属性,发现
[错误版]User:private int birthday;//数据类型错了
[正确版本]User:private Date birthday;
发现第二个问题:
[错误版本]UserMapper.java:public void save();//没写参数
[正确]UserMapper.java:public void save(User user);
发现第三个问题:
[错误版本]\TypeHandlerDemo.java:mapper.save();//没写参数
[正确版].java:mapper.save(user);
发现第四个问题
[错误版本]com.it.handler//一次创建了一个包.
[正确版]com/it/handler//分别创建com包,com.it包,com.it.handler包
[问题已解决]
复盘:不骄不躁,耐心排查.
- 元素类型为 "mapper" 的内容必须匹配
[错误版]
<select id="findall" resultType="user"/>
\select * from user
//缺了下标签
[正确版本]
<select id="findall" resultType="user">
select * from user
</select>
- public class Order {
private int id;
private int total;
private int uid;
//OVER HERE!!!
private User user;
...
}
- 运行没报错,但结果与预期不符
Figure 9: image-20211231180318331
[错误版]
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// PageHelper.startPage(2, 3);
List<User> userlist=mapper.findall();
PageHelper
PageHelper.startPage(2, 3);
[正确版本]
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
PageHelper.startPage(2, 3);
List<User> userlist=mapper.findall();
// PageHelper
// PageHelper.startPage(2, 3);
PageHelper.startPage () 必须加在执行查询sql语句(mapper.xx();)方法之前。
- idea中模块的icon变成灰色,无法新建类
设:有问题的模块为MBbasic,现用名称MBbasic,曾用名MBbasicM
[]方案A:C一下,多个网友的回答是file-setting-build..-maven-ignore..-取消对相应pom文件的勾选.检查过了,全都是没有勾选状态,不是这个问题
[有效]方案B:打开pom.xml,查看<module>标签中的模块名称是否和实际名称MBbasic一致
复盘原因:重命名模块后,pom.xml没有自动更新为新名称MBbasic,导致pom.xml中的模块名称MBbasicM和实际名称不一致,导致idea无法正常使用相应模块
未解决
- 解决报错通用流程
[]方案A:仔细检查相关代码有无错漏
[]方案B:借鉴网友回答,查看API手册
[]方案Y:延期处理
- already contains value
当前课程:注解开发多表查询
案发现场:mySpringB-HAnno-AnnoDemo
报错信息:
Mapped Statements collection already contains value for com.it.mapper.UserMapper.update.
please check com/it/mapper/UserMapper.xml and com/it/mapper/UserMapper.java (best guess)
[]方案A:百度一下,多个网友给的回答是xml中的CRUD标签的id重复了.检查过了,不是这个原因.
[]方案B:
回看视频(e188),查漏补缺.发现原因可能在于UserMapper.xml已删除,但核心文件中没有修改<mappers>.映射关系原本体现于UserMapper.xml,此文件删除后,替代代码还没写好.
<package name=”...”/>
已补充以上代码,依然报错
[]方案C:简化代码,注释掉新代码,运行基本代码,运行一次放开一行新代码,以便查看出错位置.
基本代码运行报错,
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
System.out.println(123);
//报文:already contains value
[]方案D:仔细检查代码有没有错漏之处
[]方案E:重启idea重启电脑
[]方案Y:延期处理
视频梗概
150,核心文件,标签释义
151,对照mapper.xml示意图的讲解
152-155,[mybatis的增删改查-插入数据],mybatis对数据库做增删改操作,以及一个小结
156-161,讲解核心文件sqlMapConfig.xml,其中的标签释义
这一节本应该一开始就讲的,这个文件不配好,查增改删根本不能做.也是报错Could not find resource com/xxx/xxxMapper.xml的原因
162,MyBatis测试类的讲解,Resources.getSourceAsStream->inputStream->sqlSessionFactoryBulider.build->sqlSession->openSession->xxMapper...
自动\手动提交事务
163,[剧情过渡]复现三层架构的写法,视频结尾说,有了MyBatis,可以使用代理接口的方式实现三层架构.UserMapperImpl.java,在dao包下.里面写什么?之前写在测试类里的那些(inputStream,sqlSsseion等),现在写在这个实现类里.实际工作中也是写在实现类里,而不是测试类
164,[描述]代理开发方式介绍
165,讲解mapper的4个规范,在此之前写的代码基本符合这个规范,因此讲一遍就好.
早点讲这个,后面说代理借口开发正好用上用多好.先做后说真是让人前期很懵,核心文件sqlMapConfig.xml也是,写好了也用过了,才来讲解.
166,强调了一下4个对应的关系
167,[动态sql],[mapper,dynamic sql,if,choose,trim,],以user的findByCondition为例讲解动态sql语句,未运行,不用运行,代码还有未解决的问题
168,动态sql之if上一集的遗留问题就是查询条件不是全部只有部分时会出现的问题.这一集用动态sql解决这个问题.也就是.练习时报错Type interface com.it.mapper.UserMapper is not known to the MapperRegistry.
169,[动态sql之foreach]
170,[动态SQL之include]
171,知识小结
172,173,typeHandler,-1-介绍typeHandler,-2-提出需求,搭建练习所需要的环境
174,-1-提出操作步骤, -2-编写并讲解DateTypeHandler.java
进度: 运行模块config的test1报错, 报错指向配置文件, save方法未写完整
175,核心配置文件之标签之pagehelper分页功能
176,进行编程
177,获得与分页相关的参数
178,知识小结
179,开始多表操作系列: 多表操作之一对一之一对一模型
180,多表操作 - 一对一表间关系 - 搭建开发环境
181,[重点]]多表操作 - 一对一表间关系 - 开发
182,<association><javaType>标签
183,<collection><ofType>一对多表间关系
184,MyBatis多对多查询
185,知识小结
186,注解开发/介绍
187,复习基本的MyBatis的CRUD操作
188,以xml实现的CRUD,改成以注解实现CRUD
189,[讲解原理] MyBatis的复杂查询以及一对一的多表查询开发操作, <resultMap>->@Results, 测试类: MyBatisTest2, 根据给定条件查2个表: user,order.
190, <association>->@, 根据order表中的一个外键字段查user表, 相关代码参看itheimaAnno.OrderMapper.java
191,相关代码参看itheimaAnno.UserMapper.java, 测试类: MyBatisTest3
192,
193,
END
更多推荐
MyBatis学习笔记 (第1刷, 2021.01)(完整版)
发布评论