1. MyBatis介绍
- 1. MyBatis完成CRUD(掌握)
- 2. MyBatis的核心对象(掌握)
- 3. MyBatis使用细节(掌握)
- ORM概述
2.1. 流行的ORM框架
1.JPA:本身是一种ORM规范,不是ORM框架.由各大ORM框架提供实现.
2.Hibernate:目前最流行的ORM框架.设计灵巧,性能一般(自己去控制性能,不是很好控制),文档丰富.(完全自动操作)
Hibernate是一个完整的ORM框架,常规CRUD我们不需要写一句SQL;
3.MyBatis:本是apache的一个开源项目iBatis,提供的持久层框架包括SQL Maps和Dao,允许开发人员直接编写SQL(更好灵活).(Sql操作方式)
MyBatis 并不是一个完整的ORM框架,因为我们还需要自己去写全部SQL
2.2. JDBC操作数据库缺陷
首先,通过jdbc也能实现对象实体和数据库关系的映射.那就是采用硬编码方式,为每一种可能的数据库访问操作提供单独的方法。 也就是各种Dao(UserDao DeptDao等)。
最大的缺点就是:
1、sql写在JAVA代码中改修改sql必须修改代码,需要重新编译。
2、有很多重复性的操作(比如获取连接,释放资源等)
2.3. ORM框架的操作数据库关系方式有很多种,常用的有两种
2.3.1. Sql操作方式(对jdbc进行封装)(mybatis的实现方式)
把SQL配置到配置文件中,通过不同SQL中完成对象实体和数据库关系相互转换的操作。
2.3.2. 完整操作(JPA、Hibenate实现方式)
直接映射的是对象实体和数据库关系映射。操作数据库关系,不用写SQL由框架自己生成。
2.4. ORM框架工作原理
1、以一定的映射方式,把实体模型和数据库关系的映射
2、ORM框架启动时加载这些映射和数据库配置文件
3、ORM通过对最原生jdbc的封装提供更加便利的操作API
4、Dao通过ORM提供的便捷API以对象的方式操作数据库关系。
- MyBatis的认识
3.1. MyBatis的起源
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。
iBATIS提供的持久层框架包括SQL Maps(XML映射配置)和Data Access Objects(Dao)
3.2. MyBatis的介绍
MyBatis 是一个支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。
MyBatis 消除了几乎所有的JDBC代码和手工设置参数以及结果集的检索。
MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
MyBatis不能自动创建表,如果能够自动建表,必须自己先准备好建表的sql语句。
- MyBatis完成CRUD
4.1. 操作前的准备工作
创建一个java项目?略过
4.1.1. 导入相应的9个jar包
MyBatis是一个框架,咱们说了。在Java中框架就是一组Java类最后打成jar包。因此,不只是这个框架,以后咱们学习的所有框架。在使用前都要先导入相应 的jar包。
在导入jar包之前,我们得先说一下,MyBatis是操作数据库的框架。咱们以前学JDBC的时候说过:要操作数据库,一定不要忘了导入相应的数据库驱动包。
注:驱动包就是各大数据库厂商根据JDBC规范实现的jar包(忘了的同学可以去看JDBC第一天的笔记)
然后找到MyBatis(相关文件我们已经准备好,大家也可以到网上进行自行下载),再导入MyBatis的核心包与依赖包。
下图为我们使用MyBatis要导入的包:
4.1.2. 准备相应的表
咱们对数据库进行操作,肯定需要准备表。这没啥好说的。
现在直接引入我们准备好的product表即可:
4.1.3. 准备相应的domain
创建一个Product对象,和数据库的表对应
注:类的名称和类型都和我们的product表相对应匹配
public class Product {
private Long id;
//商品名称
private String productName;
//品牌
private String brand;
//供应商
private String supplier;
//零售价
private Double salePrice;
//进价
private Double costPrice;
//折扣比例
private Double cutoff;
//商品分类编号
private Long dir_id;
//提供getter与setter...
}
4.2. 小结
准备步骤:
1 导包
2 建表(product)
3 domain(Product)
4 准备dao层(CRUD)
5 测试(不是必需的)
注意:我们要引哪些包?
1 一定要引入驱动包(不要忘了)
2 导入mybatis的核心包
3 导入mybatis的依赖包
4.3. product的Dao层准备
/**
* 商品的持久操作
*/
public interface IProductDao {
/**
* 添加一个商品
*/
void save(Product p);
/**
* 更新一个商品
*/
void update(Product p);
/**
* 删除一个商品
*/
void delete(Long id);
/**
* 得到一个商品
*/
Product get(Long id);
/**
* 得到所有商品
*/
List<Product> getAll();
}
- MyBatis核心配置文件
5.1. 看文档
一切准备就绪。接下来就是开始使用MyBatis了。但是问题来了,怎么用呢?
该文档虽然只有50多页,但是已经足够咱们学习了。
先来入个门吧:入门开始,除了介绍什么是MyBatis之后,就在说一个核心对象:SqlSessionFactory,接下来,咱们就是要想方设法拿到这个核心对象。
那SqlSessionFactory对象怎么拿到:直接找到文档中的从 XML 中构建 SqlSessionFactory这一小节开始即可。
5.2. 从这一节中我们可以看出以下几个点:
1 我们需要准备一个核心的xml文件
2 拿到SqlSessionFactory之前需要读取核心的xml配置文件
3 需要构造者(SqlSessionFactoryBuilder)来创建它
5.3. MyBatis-Config.xml
好了,大概介绍完毕后,我们可以开始准备核心配置的xml文件了
在资源文件夹下面创建一个文件,取名为MyBatis-Config.xml
以把文档中的配置拷备过来(先做了解测试,等功能可以用起来后,再自己去写这个配置)
5.4. 配置MyBatis-Config.xml提示信息
5.5. 核心配置的一个简单介绍:
我们需要准备几个东西需要一个环境environments
environments 里面两个内容(transactionManager ,dataSource )
dataSource : driver,url,username,password(连接数据库的最小单位)
<configuration>
<!-- 环境们 (很多环境的意思)
default:默认使用哪一个环境(必需对应一个环境的id)
-->
<environments default="development">
<!--
一个环境 id:为这个环境取唯一一个id名称
-->
<environment id="development">
<!--
事务管理 type:JDBC(支持事务)/MANAGED(什么都不做)
-->
<transactionManager type="JDBC" />
<!-- 数据源, 连接池 type(POOLED):MyBatis自带的连接池 -->
<dataSource type="POOLED">
<!-- 连接数据库的参数 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///mydb" />
<property name="username" value="root" />
<property name="password" value="admin" />
</dataSource>
</environment>
</environments>
<!-- 这个mappers代表的是相应的ORM映射文件 -->
<mappers>
<mapper resource="cn/itsource/domain/ProductMapper.xml" />
</mappers>
</configuration>
5.6. 抽取数据库信息配置文件
现在咱们的关于数据库连接信息已经在配置文件(XML)中,但是更多时候,我们还是会把配置文件的信息放到db.properties中。(由于properties的结构简单,便于修改,而这个文件只放数据库的连接信息也更好的体现了职责分离)。
其实,在官方文档的核心文件配置,直接就是使用的推荐properties的方式
只需要我们做如下修改即可:
5.6.1. MyBatis-Config.xml
<configuration>
<!-- 引入Properties文件 -->
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!-- 根据key拿到properties中的value值 -->
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/itsource/domain/ProductMapper.xml"/>
</mappers>
</configuration>
5.6.2. db.properties
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql:///test0303
db.username=root
db.password=admin
5.7. 映射文件
核心文档已经搭建准备就绪,心里还有一点小激动。
但是总是觉得,少了点什么? 是什么呢?
请大家回顾与分析我们刚才学习的内容:
MyBatis是一个ORM映射框架,请问ORM体现在哪?
核心文件中有一个mappers,它指向了一个映射文件。映射文件在哪?
不是说好的MyBatis要写SQL语句么?SQL语句又在哪里?
一切的一切都会出现在我们的下一个章节:对象与关系的映射!敬请关注。
现在直接写xml是没有提示了,在xml的约束中,咱们讲过,当有约束的时候,xml就会有提示。
提示:出门再拐 在xml那一章的schema与dtd约束
而现在咱们的约束是在网络上。在Eclipse中,我们可以找到相应的约束文件,然后配置到自己本地即可。
5.8. 对象与关系的映射(ORM)
接下来,解决上一章的几个问题。
直接找到我们文档中的探究已映射的SQL语句,在这里,我就可以看到一段xml(如下图),这个xml就是咱们需要的映射文件,它就可以体现出ORM,并且在这里面,也可以愉快的写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">
<!--
这个Mapper的主要功能就是写sql
mapper:根
namespace:命令空间 (用来确定唯一) 以前这个是可以不加的,现在必需加
namespace的值,规则的:映射文件XxxMapper.xml所在的包+domain类名+Mapper
-->
<mapper namespace="cn.itsource.mybatis.day1._1_hello.ProductMapper">
<!--
select : 这里面写查询语句
id:用来确定这条sql语句的唯一
以后我们确定唯一,也就是找sql语句 : namespace +.+ id
例: cn.itsource.mybatis.day1._1_hello.ProductMapper.get
parameterType : 传入的参数类型 long:大Long _long:小long (具体的对应请参见文档)
resultType : 结果类型(第一条数据返回的对象类型) 自己的对象一定是全限定类名
-->
<select id="get" parameterType="long" resultType="cn.itsource.domain.Product">
select * from product where id = #{id}
</select>
</mapper>
5.9. 在上述文件中,希望大家注意几个规范:
① 我们的映射文件一般情况下是和它对应的domain实体类在同一个层级
② 这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
③ namespace的名称为了确定唯一性,请大家根据我的要求取名
如我们有一个类:
cn.itsource.domain.Product / cn.itsource.domain.Student
那这里取名应该是:
cn.itsource.domain.ProductMapper /cn.itsource.domain.StudentMapper
④ 除了MyBatis支持的类型,其它的类型都通通使用全限定名
- 完成数据的CRUD
核心文件有了,映射文件也有了。现在可以来完成咱们的CRUD了吧!
但是应该从哪里开始好呢?
还记得咱们前面说过需要的核心对象SqlSessionFactory吧
咱们说过,需要通过它去拿到一个SqlSession对象(相当于JDBC的连接)
必需要有SqlSession这个对象,我们才可以去执行相应的Sql
6.1. 拿到SqlSession对象
官方文档从XML 中构建 SqlSessionFactory这一章中,除了配置的核心xml,在上面我们还可以看到几句代码(如下图),现在咱们就来详细分析一下这几句代码是什么意思:
我们简单解释一下上面的代码:读取核心文件,然后再通过SqlSessionFactoryBuilder构建者来创建一个SqlSessionFactory工厂。
注:上面的sqlMapper其实是一个SqlSessionFactory工厂对象(它取名不是很直观)
官方文档从SqlSessionFactory 中获取 SqlSession这一章中,我们可以看到代码(下图),然后再拿到SqlSession,并且在这里面,还附上了咱们怎么调用sql的代码。
6.2. 工具类的抽取MyBatisUtils
对于MyBatis的工具类抽取,咱们直接使用静态工具的单例模式。
注:几种单例模式的区别与使用(单例工具与静态工具的区别),大家可以去看基础加强那天的课程。
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtils {
// 保证SqlSessionFactory是单例
private static SqlSessionFactory sqlSessionFactory;
// SqlSessionFactory类似于JPA的EntityManagerFactory,Hibernate的SessionFactory
// SqlSession 类似于JPA的EntityManager,Hibernate的Session
static {
try {
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("解析MyBatis的配置文件或者映射文件出现异常:" + e.getMessage());
}
}
// 对外提供一个类
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
6.3. 查询一条数据
根据上面我们get到的技能,使用MyBatis查询一条数据!
大家要注意咱们传过去的参数,还有在SQL接收的参数!【课堂分析】
传过去的变量名称和#里面的字符串名称不是一回事!
讲到这里,咱们再对整个MyBatis的流程再进行一次分析。
①:我们需要核心文件(提供联系数据库的环境)
②:需要映射文件(提供ORM与运行的SQL语句)
③:拿到SqlSession对象,用于执行SQL
@Override
public Product get(Long id) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSession();
return sqlSession.selectOne(NAME_SPACE + "get", id);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("ProductDaoImpl.get出现异常:" + e.getMessage());
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
6.4. junit来一个测试(必须的)
写代码要测试,这是一个好习惯!
public class ProductDaoTest {
IProductDao productDao = new ProductDaoImpl();
@Test
public void testGet() {
Product product = productDao.get(1L);
System.out.println(product);
}
}
6.5. 查询所有数据
6.5.1. 代码
@Override
public List<Product> getAll() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSession();
return sqlSession.selectList(NAME_SPACE + "getAll");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("ProductDaoImpl.get出现异常:" + e.getMessage());
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
6.5.2. 映射文件
<!-- 返回类似仍然是Product:domain类 -->
<select id="getAll" resultType="cn.itsource.mybatis.day1._1_hello.Product">
select * from product
</select>
6.5.3. 测试
@Test
public void testGetAll() {
List<Product> list = productDao.getAll();
for (Product product : list) {
System.out.println(product);
}
}
6.6. 添加一条数据
注:添加的时候一定要记住提交事务(配置事务、表结构支持事务)
JDBC的事务是自动提交的,而JPA、Hibernate、MyBatis事务都是需要手动提交的
6.6.1. 代码
@Override
public void save(Product product) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSession();
sqlSession.insert(NAME_SPACE + "save", product);
// JDBC的事务是自动提交的,而JPA、Hibernate、MyBatis事务都是需要手动提交的
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("ProductDaoImpl.get出现异常:" + e.getMessage());
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
6.6.2. 映射文件
<!-- void save(Product product); -->
<insert id="save" parameterType="cn.itsource.mybatis.day1._1_hello.Product">
<!-- #{productName}==product.getProductName() -->
insert into product(productName,salePrice,costPrice,cutoff,supplier,brand,dir_id)
values
(#{productName},#{salePrice},#{costPrice},#{cutoff},#{supplier},#{brand},#{dir_id})
</insert>
6.6.3. 测试
@Test
public void testSave() {
Product product = new Product();
product.setBrand("大力牌");
product.setCostPrice(30.0);
product.setCutoff(0.8);
product.setDir_id(1L);
product.setProductName("000000");
product.setSalePrice(60D);
product.setSupplier("东莞供应商");
productDao.save(product);
}
添加数据的有时候咱们需要拿到当前数据的主键。咱们先移步到MyBatis细节一章的拿到返回主键部分!
6.7. 修改一条数据
6.7.1. 代码
@Override
public void update(Product product) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSession();
sqlSession.update(NAME_SPACE + "update", product);
// JDBC的事务是自动提交的,而JPA、Hibernate、MyBatis事务都是需要手动提交的
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("ProductDaoImpl.get出现异常:" + e.getMessage());
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
6.7.2. 映射文件
<!-- void update(Product product); -->
<update id="update" parameterType="cn.itsource.mybatis.day1._1_hello.Product">
<!-- #{productName}==product.getProductName() -->
update product set productName=#{productName},salePrice=#{salePrice},costPrice=#{costPrice},
cutoff=#{cutoff},supplier=#{supplier},brand=#{brand},dir_id=#{dir_id}
where id=#{id}
</update>
6.7.3. 测试
@Test
public void testUpdate() {
Product product = productDao.get(1L);
System.out.println(product);
product.setBrand("大力牌");
product.setCostPrice(30.0);
product.setCutoff(0.8);
product.setDir_id(1L);
product.setProductName("000000");
product.setSalePrice(60D);
product.setSupplier("东莞供应商");
productDao.update(product);
product = productDao.get(1L);
System.out.println(product);
}
6.8. 删除一条数据
6.8.1. 代码
@Override
public void delete(Long id) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSession();
sqlSession.delete(NAME_SPACE + "delete", id);
// JDBC的事务是自动提交的,而JPA、Hibernate、MyBatis事务都是需要手动提交的
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("ProductDaoImpl.delete出现异常:" + e.getMessage());
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
6.8.2. 映射文件
<!-- void delete(Long id); -->
<delete id="delete" parameterType="id">
delete from product where id=#{id}
</delete>
6.8.3. 测试
@Test
public void testDelete() {
productDao.delete(1L);
Product product = productDao.get(1L);
System.out.println(product);
}
6.9. CRUD注意事项
下面的点都很重要,是大家在使用MyBatis的时候经常出现的点。希望大家引起重视。出现问题的时候过来好好的来找。基本咱们使用MyBatis中出的错都在这里。
使用框架的时候配置信息变多,在配置里写的都是字符串,而且经常是要对应的。因为,这里希望大家要切记:写的时候细心,出现错误找字符串要耐心,
1 主配置中未配置相应的mapper(当然,这个路径也可能写错)
2 在代码中调用Sql的时候路径写错
3 Sql写错,这个应该还好找
4 当我们在配置文件中很多地方如果写错,即便是你还没有使用也可能会报错
5 写Sql的标签不需要全部一致(如添加不一定必需使用insert),但是它的属性会不同
6 在传入与返回参数时全限定类名写错
在开发的时候,要边做边测试。 在某一步出现错误后,删除新加的代码看有没有问题,如果删除部分代码后运行成功,就相应的可以缩小排错的范围。
- MyBatis三大核心对象
SqlSessionFactory类似于JPA的EntityManagerFactory,Hibernate的SessionFactory
SqlSession 类似于JPA的EntityManager,Hibernate的Session
详细的认识一下MyBatis的几个核心类:
7.1. SqlSessionFactoryBuilder
建造者模式:我们最后拿到的这个对象是非常复杂的. 用这个建造者就它先为我们把这些复杂的代码完成.
这个类可以被实例化,使用和丢弃。一旦你创建了SqlSessionFactory后,这个SqlSessionFactoryBuilder类就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围(也就是本地方法变量)。
你可以重用SqlSessionFactoryBuilder来创建多个SqlSessionFactory实例,但是最好的方式是
不需要保持它一直存在来保证所有XML解析资源,因为还有更重要的事情要做。
7.2. SqlSessionFactory
一旦被创建,SqlSessionFactory应该在你的应用执行期间都存在。没有理由来处理或重新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次。这样的操作将被视为是非常糟糕的。因此SqlSessionFactory的最佳范围是应用范围。
有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。然而这两种方法都不认为是最佳实践。这样的话,你可以考虑依赖注入容器,比如Google Guice或Spring。这样的框架允许你创建支持程序来管理单例SqlSessionFactory的生命周期。
7.3. SqlSession
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。
绝对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中。
也绝不能将SqlSession实例的引用放在任何类型的管理范围中,比如Serlvet架构中的HttpSession。
如果你现在正用任意的Web框架,要考虑SqlSession放在一个和HTTP请求对象相似的范围内。换句话说,基于收到的HTTP请求,你可以打开了一个SqlSession,然后返回响应,就可以关闭它了。关闭Session很重要,
为什么在这里我们要先说这三大核心对象呢,因为在我们必需要了解这三个对象的特性。才可以更好的根据这个特性来完成工具类代码。
- MyBatis的使用细节
8.1. 添加时拿到返回的主键
注:若是忘了为什么要拿到主键。可以去看JDBC第二天的课程,那里咱们当时有详细的解释。
<!--
parameterType:需要传入我们的对象
useGeneratedKeys: 是否需要主键
keyColumn:主键所在的列,可以不用配置
keyProperty:对象中的属性(代表主键的那个属性)
-->
<insert id="save" parameterType="cn.itsource.domain.Product"
useGeneratedKeys="true"
keyColumn="id"
keyProperty="id"
>
insert into product (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice)
values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
主键就直接放到返回的对象里面
8.2. Log4j日志框架
在使用MyBatis的很多时候,我们需要把日志打印出来,帮助我们进行分析与排错。特别是大家现在学习阶段,要求大家都MyBatis的日志打开。
打开后我们可以看到执行的SQL语句,可以看到我们传递的参数。
而MyBatis中打印日志使用的是Log4j
8.2.1. Log4j简介:
Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局)。
可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松地记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。
8.2.2. 日志等级
等级从低到高
TRACE:详细
Debug:调试,类似于System.out.print
Info:信息,类似于JPA打印sql等级
Warn:警告,程序可以正常运行,出现提示
Error:错误,出现异常
8.2.3. log4j.properties
要在项目中打开日志,大家在资源文件根目录下创建一个log4j.properties的文件,并把下面的代码拷备到里面。
log4j.properties(日志文件:)
log4j.rootLogger=ERROR, stdout
#log4j.rootLogger=NONE
log4j.logger.cn.itsource=TRACE 把左边包名改成你自己的包名
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
注意:在上面的标红部分是我们需要修改的,它大概表示为当前会打印哪些位置下面文件的日志。
cn.itsource:一定要根据自己的包名情况进行修改
如果配置成功,那么在MyBatis运行操作数据时就可以看到相应的日志了。
8.3. MyBatis中为一个类取别名
别名:分两种
8.3.1. 内置别名
8.3.2. 自定义别名
在我们前面传参与接收结果的时候,咱们一直是使用的全限定名。
但是MyBatis自己在使用很多类型的时候(如Integer,Boolean)却可以直接使用别名。
那么,咱们自己的写的类能不能使用别名呢?
大家可以直接找到官文文档上typeAliases这一章,有介绍我们怎么为自己的类取别名。
取别名有什么用,呵呵。我认识一个朋友,他叫做:特雷西.麦克格雷迪,我叫他麦迪
下面为取别名的代码:
<typeAliases>
<!--
将一个包下面的所有类都取上别名:<package name="cn.itsource.domain" />
alias:取的别名
type:这个别名所对应的Java类
:别名使用的时候与大小写无关
-->
<typeAlias alias="product" type="cn.itsource.domain.Product" />
<!-- 做项目的时候使用 -->
<package name="cn.itsource.mybatis.day1._2_detail" />
</typeAliases>
注:必需在主文件中设置别名,其它地方才可以使用(切记切记)
8.4. 列名与属性名不对应的解决方案resultMap
原来通过javaBean自动映射,可以使用手动映射
大家应该有注意到,前面咱们做映射文件的时候,只做了表与对象之间的联系。并没有做列与字段之间的联系。那么它们之间是怎么联系上的呢?
由于之前咱们的列名与属性名是一样的,因此框架进行了自动的识别。
那么:如果咱们的列名与属性名不一致了(对应不上),这时候应该怎么办呢?
这时候,就需要我们开发人员告诉MyBatis,我们需要把哪些列名与属性名对应上。
在MyBatis中,提供了一个resultMap的标签,就是让咱们来完成返回结果的关系对应的,使用方式如下:
<!--
返回的数据映射
type:代表是要映射的对象
id:代表唯一(过会我们要拿到它)
-->
<resultMap type="cn.itsource.domain.Product" id="productMap">
<!--
column:对应的列名
property:对应的属性名
-->
<id column="id" property="id" />
<result column="productName" property="name" />
</resultMap>
<select id="queryOne" parameterType="long" resultMap="productMap">
select * from product where id = #{id}
</select>
- 课程总结
9.1. 重点
- MyBatis CRUD
9.2. 难点
- 怎样获取主键,怎样配置
- Log4j理解
- 别名
- 常见异常
- java.lang.ClassNotFoundException: Cannot find class: id
<delete id="delete" parameterType="id">应该传入long类型,而不是id
- Caused by: org.xml.sax.SAXParseException; lineNumber: 23; columnNumber: 4; 元素类型 "select" 必须由匹配的结束标记 "</select>" 终止。
<select id="getAll" resultType="cn.itsource.mybatis.day1._1_hello.Product">
select id,productName,salePrice,costPrice,cutoff,supplier,brand,dir_id from
product
</insert>
- Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for cn.itsource.mybatis.day1._1_hello.ProductMapper.get
没有配置文件里面加载映射文件,如何开始就使用
- Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'productName' in 'class cn.itsource.mybatis.day1._2_detail.Product'
Product类里面没有'productName'属性
- 常见问题
- 没有导入数据库的驱动包
- 在XML中很多都是字符串,细心,不要写错
- 在映射文件中全限定类名可能会写错
- 找不到相应的Statement(sql语句)
- 找SQL的Statement写错了
- 在核心XML中没有找相应的映射文件
- 在我们调用Statement(sql语句的时候),经常会忘记传参
- 执行成功后,数据库却没有反映,很有可能是没有提交事务
- 可能我们忘了写执行的代码了
- 错误一定要打印出来(执行的时候没效果,但是又不报错)
- Mapper中就算一个语句没有使用,它的错也可能会影响到其它正确的语句
- 框架的错往往从后向前找
- 很多同学没有取别名,但是他一直去用
- Mysql乱码,添加字符编码:useUnicode=true&characterEncoding=UTF-8
- 课后练习
- 面试题
- mybatis相较于jdbc的优点?
把sql语句从java代码中抽取出来,方便维护。并且修改sql时不用修改java代码
不用手动设置参数和对结果集的处理。
- 扩展知识或课外阅读推荐
14.1. 扩展知识
- 以后工作是用JPA(Hibernate)还是用MyBatis呢?
- MyBatis与JPA(Hibernate)的区别?