目录
1.内容介绍
1. 为什么需要Mybatis; (了解)
2. 初识Mybatis; (了解)
3. Mybatis入门; (掌握)
4. Mybatis工具类; (掌握)
5. Mapper映射器; (掌握)
6. Mybatis使用细节; (掌握)
2.为什么需要Mybatis
1.来看一段之前JDBC写的代码:
2.问题:
(1)sql写在JAVA代码中,修改sql必须修改代码,耦合度太高;
(2)代码量多,重复性代码过多;
(3)手动设置参数,并且如果是查询操作,还需要手动转换结果,麻烦;
(4)连接资源手动关闭,麻烦【以后和Spring整合就不需要手动关闭连接了】;
3.初识Mybatis
3.1.Mybatis是什么
1.MyBatis是一个ORM的数据库持久化框架;
2.Mybatis底层还是原生的JDBC代码,对JDBC代码的封装;
3.1.1.什么是框架
1.框架(Framework)是一个框子:指其约束性。也是一个架子:指其支撑性;
2.程序中的框架,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分,从而更迅速和方便地构建完整的解决问题的方案;
3.程序中的框架其实是一系列jar包(一系列.class文件)的组合;
4.框架是一个半成品,并没有解决具体的问题,但是有了框架之后,不需要从零起步,提高了开发效率;
5.框架通常是为了解决某一个领域的问题而产生;
6.适用于团队开发,统一规范,方便维护;
综上所述:所谓的框架就是提供的一些支撑结构,通过这些支撑结构,可以解决具体的问题,但是在使用过程中要遵循一定的规范;
3.1.2.什么叫数据库持久化
1.数据持久化就是将内存中的数据模型转换为存储模型,即把内存中的数据保存到数据库中;
2.常见的数据持久化分为磁盘持久化和数据库持久化;
3.Java中最简单的就是使用原生的jdbc代码来完成数据库持久化,但是这种方式有很多问题;
3.1.3.什么是ORM
ORM:对象关系映射(Object Relational Mapping,简称ORM):是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术;
3.1.3.1.ORM框架映射方式
ORM框架操作数据库关系方式有很多种,常用的有两种:
第一种:Sql操作方式(半映射或半自动):把SQL配置到配置文件中,通过不同SQL中完成对象实体和数据库关系相互转换的操作(Mybatis的实现方式)
第二种:完整映射:直接使用对象实体和数据库关系进行映射,不用写SQL(简单的操作),由框架自己生成(JPA、Hibenate实现方式)
3.1.3.2.ORM原理
1.以一定的映射方式,把实体模型和数据库关系进行映射;
2.ORM框架启动时加载这些映射和数据库配置文件连接数据库;
3.ORM通过对最原生jdbc的封装,并提供更加便利的操作API;
4.Dao通过ORM提供的便捷API以对象的方式操作数据库关系;
3.1.3.3.常见的ORM持久化框架
1.JPA:本身是一种ORM规范,不是ORM框架,由各大ORM框架提供实现;
2.Hibernate(完整映射):目前流行的ORM框架,设计灵巧,性能一般(自己去控制性能,不是很好控制),文档丰富。Hibernate是一个完整的ORM框架,常规CRUD我们不需要写一句SQL;
3.MyBatis(半映射):本是apache的一个开源项目iBatis,提供的持久层框架包括SQL Maps(Mapper)和Dao,允许开发人员直接编写SQL,更加灵活;
3.2.Mybatis的起源
1.Mybatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github;
2.iBatis一词来源于"internet"和"abatis"的组合,是一个基于Java的持久层框架;
3.Mybatis 包括SQL Maps(Mapper)和Dao;
3.3.Mybatis的优势
1.sql语句与代码分离,存放于xml配置文件中,方便维护;
2.Mybatis消除了几乎所有的JDBC代码和手工设置参数以及结果集的检索;
3.提供XML标签,支持编写动态SQL,代替编写逻辑代码;
面试题:Mybatis相较于jdbc的优点?
1.把sql语句从java代码中抽取出来,方便维护,并且修改sql时不用修改java代码;
2.不用手动设置参数和对结果集的处理,让我们操作数据库更加简单;
3.与JDBC相比,大大减少了代码量,提高了开发效率;
4.MyBatis入门
4.1.导入相应的jar包
4.2.准备相应的表
4.2.1.准备相应的domain
1.创建一个Product对象,和数据库的表对应
2.类的名称和类型都和我们的product表相对应匹配
public class Product {
private Long id;
//商品名称
private String productName;
//品牌
private String brand;
//供应商
private String supplier;
//零售价
private BigDecimal salePrice;
//进价
private BigDecimal costPrice;
//折扣价
private Double cutoff;
//商品分类编号
private Long dir_id;
//提供getter与setter...
}
4.2.2.product的dao层准备
接口和空实现类
/**
* 商品的持久操作
* @author Administrator
*/
public interface IProductDAO {
/**
* 添加一个商品
*/
void save(Product p);
/**
* 更新一个商品
*/
void update(Product p);
/**
* 删除一个商品
*/
void delete(Long id);
/**
* 得到一个商品
*/
Product get(Long id);
/**
* 得到所有商品
*/
List<Product> findAll();
}
4.2.3.测试先行
写代码要测试,这是一个好习惯
4.3.入门实现
4.3.1.实现步骤分析
一切准备就绪。接下来就是开始使用MyBatis了。但是问题来了,怎么用呢?
查看文档:该文档虽然只有50多页,但是已经足够咱们学习了。
1.先来入个门吧:入门开始,除了介绍什么是MyBatis之后,就在说一个核心对象:SqlSessionFactory,接下来,咱们就是要想方设法拿到这个核心对象;
2.那SqlSessionFactory对象怎么拿到:直接找到文档中的从 XML 中构建 SqlSessionFactory这一小节开始即可;
3.要获取SqlSessionFactory,我们需要准备一个核心的Mybatis-config.xml文件,然后通过SqlSessionFactoryBuilder来创建,所以步骤:
(1)创建Mybatis核心配置文件(Mybatis-config.xml),并配置环境;
(2)加载核心配置文件
(3)创建一个SqlSessionFactoryBuilder对象;
(4)通过SqlSessionFactoryBuilder对象构建一个SqlSessionFactory对象
(5)创建Mapper映射文件,并配置;
(6)通过SqlSessionFactory获取SqlSession执行映射SQL
4.3.2.实现
核心配置文件:MyBatis-Config.xml
<configuration>
<!-- 引入配置文件信息,这里不能加classpath:。
resource:引入类路径下的资源,即classpath,所以不需要写classpath:
url:引入网络路径或磁盘路径下的资源
-->
<properties resource="db.properties"></properties>
<!-- 环境们 (很多环境的意思)
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" />
-->
<!-- 连接数据库的参数:使用属性文件的方式 -->
<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代表的是相应的ORM映射文件 -->
<mappers>
<mapper resource="cn/itsource/domain/ProductMapper.xml" />
</mappers>
</configuration>
属性文件:db.properties
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql:///test0303
db.username=root
db.password=admin
映射文件:
1.我们的映射文件(也称之为mapper文件)一般情况下是和它对应的domain实体类在同一个包下;
2.这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
例如实体类有:
cn.itsource.domain.Product
映射文件名为:
cn/itsource/domain/ProductMapper.xml
3.namespace的名称通常是接口的完全限定名;
4.除了MyBatis支持的类型,其它的类型都通通使用全限定
<?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的值:接口的完全限定名
-->
<mapper namespace="cn.itsource.dao.IProductDao">
<!--
select :这里面写查询语句
id:用来确定这条sql语句的唯一
以后我们确定唯一,也就是找sql语句 : namespace + id
例: cn.itsource.mybatis.day1._1_hello.IProductDao.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>
入门代码:
@Override
public Product get(Long id) {
SqlSession session = null;
try {
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
session = sqlSessionFactory.openSession();
// 两个参数:mapper的nameSpace+id的路径,和需要的参数
return session.selectOne(NAME_SPACE+"get", id);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("使用get方法出错:" + e.getMessage());
} finally {
if (session != null) {
session.close();
}
}
}
4.4.其他实现
package cn.itsource.mybatis._01_hello.dao.impl;
import cn.itsource.mybatis._01_hello.dao.IProductDao;
import cn.itsource.mybatis._01_hello.domain.Product;
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.Reader;
import java.util.List;
/**
* dao实现
*
* insert:添加,事务控制
* delete:删除,事务控制
* update:修改,事务控制
* selectOne:查询一个
* SelectList:查询多个
*/
public class ProductDaoImpl implements IProductDao {
@Override
public void save(Product product) {
SqlSession sqlSession = null;
try {
//1 准备配置文件 ok
//2 创建SqlSessionFactory
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//3 获取sqlSession做操作
sqlSession = sqlSessionFactory.openSession();
//表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
sqlSession.insert("cn.itsource.dao.IProductDao.save",product);
//提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Override
public void remove(Long id) {
SqlSession sqlSession = null;
try {
//1 准备配置文件 ok
//2 创建SqlSessionFactory
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//3 获取sqlSession做操作
sqlSession = sqlSessionFactory.openSession();
//表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
sqlSession.delete("cn.itsource.dao.IProductDao.remove",id);
//提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Override
public void update(Product product) {
SqlSession sqlSession = null;
try {
//1 准备配置文件 ok
//2 创建SqlSessionFactory
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//3 获取sqlSession做操作
sqlSession = sqlSessionFactory.openSession();
//表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
sqlSession.update("cn.itsource.dao.IProductDao.update",product);
//提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Override
public Product loadById(Long id) {
SqlSession sqlSession = null;
try {
//1 准备配置文件 ok
//2 创建SqlSessionFactory
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//3 获取sqlSession做操作
sqlSession = sqlSessionFactory.openSession();
//表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
return sqlSession
.selectOne("cn.itsource.dao.IProductDao.loadById",id);
}catch (Exception e){
e.printStackTrace();
}finally {
if (sqlSession != null) {
sqlSession.close();
}
}
return null;
}
@Override
public List<Product> loadAll() {
SqlSession sqlSession = null;
try {
//1 准备配置文件 ok
//2 创建SqlSessionFactory
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//3 获取sqlSession做操作
sqlSession = sqlSessionFactory.openSession();
//表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
return sqlSession
.selectList("cn.itsource.dao.IProductDao.loadAll");
}catch (Exception e){
e.printStackTrace();
}finally {
if (sqlSession != null) {
sqlSession.close();
}
}
return null;
}
}
package cn.itsource.mybatis._01_hello.dao;
import cn.itsource.mybatis._01_hello.dao.impl.ProductDaoImpl;
import cn.itsource.mybatis._01_hello.domain.Product;
import org.junit.Test;
/**
* 打印快捷方式:obj.sout
* 快速省略测试:类里面-右键-goto-junit4-勾上
*/
public class IProductDaoTest {
IProductDao productDao = new ProductDaoImpl();
@Test
public void save() {
Product product = productDao.loadById(18L);
product.setId(null);
product.setProductName("yhptest......");
productDao.save(product);
}
@Test
public void remove() {
Product product = productDao.loadById(19L);
System.out.println(product);
productDao.remove(19L);
product = productDao.loadById(19L);
System.out.println(product);
}
@Test
public void update() {
Product product = productDao.loadById(22L);
System.out.println(product);
product.setProductName("yhptest......edit");
productDao.update(product);
product = productDao.loadById(22L);
System.out.println(product);
}
@Test
public void loadById() {
//obj.sout
System.out.println(productDao.loadById(1L));
}
@Test
public void loadAll() {
for (Product product : productDao.loadAll()) {
System.out.println(product);
}
}
}
4.5.注意
配置XML中的约束,使其有提示:
5.Mybatis工具类
5.1.MybatisUtil抽取
5.1.1.为什么要抽取
1.其实每个Dao的方法都要获取SQLSession,并且使用完都要关闭,对于像获取和关闭等操作都应该交给工具处理;
5.1.2.抽取理论分析
SqlSessionFactoryBuilder:
建造者模式:我们最后拿到的这个对象是非常复杂的. 用这个建造者就它先为我们把这些复杂的代码完成。这个类可以被实例化,使用和丢弃。一旦你创建了SqlSessionFactory后,这个类对象就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围(也就是本地方法变量)。你可以重用SqlSessionFactoryBuilder来创建多个SqlSessionFactory实例,但是最好的方式是不需要保持它一直存在来保证所有XML解析资源,因为还有更重要的事情要做;
SqlSessionFactory:
一旦被创建,SqlSessionFactory应该在你的应用执行期间都存在。没有理由来处理或重新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次。这样的操作将被视为是非常糟糕的。因此SqlSessionFactory的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。然而这两种方法都不认为是最佳实践。这样的话,你可以考虑依赖注入容器,比如Google Guice或Spring。这样的框架允许你创建支持程序来管理单例SqlSessionFactory的生命周期;
SqlSession
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中。也绝不能将SqlSession实例的引用放在任何类型的管理范围中,比如Serlvet架构中的HttpSession。如果你现在正用任意的Web框架,要考虑SqlSession放在一个和HTTP请求对象相似的范围内。换句话说,基于收到的HTTP请求,你可以打开了一个SqlSession,然后返回响应,就可以关闭它了。关闭Session很重要;
5.1.3.抽取
5.2.使用工具完成CRUD
5.2.1.查询一条数据
sql
代码
5.2.2.查询所有数据
sql
代码
5.2.3.添加一条数据
注意:添加的时候一定要记住提交事务(配置事务、表结构支持事务)
sql
代码
5.2.4.修改一条数据
sql
代码
5.2.5.删除一条数据
sql
代码
6.SQL映射器Mapper
6.1.引入
引入:之前通过Mybatis操作数据库的时候,除了写接口,还要写实现类。MyBatis基于动态代理机制,让我们无需再编写Dao的实现,但是必须要遵循一定的规范:
1.传统Dao接口,现在名称统一以Mapper结尾:例如:IUserDao --> UserMapper
2.还有我们映射器配置文件要和映射器在同一个包:
(1)包:cn.itsource.mapper中(UserMapper接口 和 UserMapper.xml)
3.UserMapper.xml中namespace直接写UserMapper接口的的完全限定名;
映射文件:
<mapper namespace="cn.itsource.mybatis.mapper.UserMapper">
<select id="接口的方法名" parameterType="long" resultType="User">
Select * from t_user where id = #{id}
</select>
</mapper>
6.2.映射器实现步骤
- 1.根据需求,创建模型相关的Mapper接口,例如:UserMapper;
- 2.在同包下编写映射文件,例如:UserMapper.xml;
(1)Mapper映射文件的命名空间,必须和接口的"完全限定名"一致;
(2)定义sql标签的id,需要和"接口的方法名"一致; - 3.在Mybatis核心配置文件中配置(或注册)Mapper映射文件;
- 4.测试;
友情提示:最好不要在mapper接口中使用方法重载,因为sql标签的id即为方法名,写重载方法容易出问题;
6.3.实现
接口实现方式一(传统):
接口实现方式二(映射器):
7.Mybtis使用细节
7.1.查看MyBatis运行日志
7.1.1.为什么需要日志
在使用MyBatis的很多时候,我们需要把日志打印出来,帮助我们进行分析与排错。特别是大家现在学习阶段,要求大家都MyBatis的日志打开;
7.1.2.常见的日志框架
- 1.System.out.print(“xxxx”)
- 2.写一个日志框架 dblLog.jar(yhptest)
Log log = LogFactory.getLog(this.class)
log.error/Info/warn… - 3.写一个日志框架 dzlLog.jar(ttttt)
Log log = Factory.getLog(this.class)
log.error/Info/warn… - 4.定义标准
(1)新写的日志框架按照日志标准来做;
(2)以前的日志框架使用适配器来做适配; - 5.标准:slf4j(标准) – commons.logging,log4j(实现)
7.1.3.Log4j日记实现
- 1.Log4j主要用于日志信息的输出。可以将信息分级别(严重fatal、错误error、警告warn、调式debug、信息info)按不同方式(控制台、文件、数据库)和格式输出;
- 2.实现步骤如下:
(1)导入log4j的jar包(3个);
(2)在classpath下添加log4j.properties【名字不能改】;
(3)日志级别:debug(调试时用)、info、warn、error(运行时用)
(4)在日志中我们可以看到执行的SQL语句,可以看到我们传递的参数 - 3.Log4j主要有以下3部分组件构成:
(1)日志器(Logger):负责消息输出,提供了各种不同级别的输出方法;
(2)输出器(Appender):负责控制消息输出的方式,例如输出到控制台、文件输出等;
(3)布局器(格式器,Layout):负责控制消息的输出格式; - 4.要在项目中打开日志,大家在资源文件根目录下创建一个log4j.properties【名称不要修改】的文件,并把下面的代码拷备到里面:
#日志器logger #輸出器appender #布局器layout
#1.控制台输出
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=info,myconsole
#指定输出器
#log4j.appender.myconsole=org.apache.log4j.ConsoleAppender
#指定布局器
#log4j.appender.myconsole.layout=org.apache.log4j.SimpleLayout
#2.文件输出.txt
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=error,myfile
#指定输出器
#log4j.appender.myfile=org.apache.log4j.FileAppender
#log4j.appender.myfile.File=E:\\log4j.txt
#指定布局器(普通布局表示文本输出)
#log4j.appender.myfile.layout=org.apache.log4j.SimpleLayout
#3.文件输出.html
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=error,myhtml
#指定输出器
#log4j.appender.myhtml=org.apache.log4j.FileAppender
#log4j.appender.myhtml.File=D:\\log4j.html
#指定布局器(网页布局)
#log4j.appender.myhtml.layout=org.apache.log4j.HTMLLayout
#4.控制台输出+文件输出.txt
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=error,con,file
#指定输出器
#log4j.appender.con=org.apache.log4j.ConsoleAppender
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=D\:\\log4j.txt
#指定布局器(网页布局)
#log4j.appender.con.layout=org.apache.log4j.SimpleLayout
#log4j.appender.file.layout=org.apache.log4j.SimpleLayout
#5.控制台输出+自定义布局
log4j.rootLogger=DEBUG,my
#指定输出器
log4j.appender.my=org.apache.log4j.ConsoleAppender
#指定布局器(自定义布局)
#指定布局为自定义布局
log4j.appender.my.layout=org.apache.log4j.PatternLayout
#指定在自定义布局的格式,%d -- 表示当前系统时间,%t -- 执行该业务的线程名称,%p -- 日记器的级别,-5 -- 5表示输出字符的个数,符号表示右对齐
#%c -- 表示指定业务所在的类的完全限定名(包名.类名),%m -- 输出额外信息,%n -- 表示换行
log4j.appender.my.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
#设置package(可以是自定义的包也可以是api的包)输出级别
log4j.logger.org.springframework=info
log4j.logger.cn.itsource=debug
注意:在上面的标红部分是我们需要修改的,它大概表示为当前会打印哪些位置下面文件的日志;如果配置成功,那么在MyBatis运行操作数据时就可以看到相应的日志了;
7.2.MyBatis中使用别名
1.别名就是为类取得小名,以后可以使用小名代替真实名称,在Mybatis中,将实体类的名称简化,方便开发,别名分为内置别名和自定义别名;
7.2.1.内置别名
7.2.2.自定义别名
<typeAliases>
<!-- 单个配置:测试时使用 -->
<typeAlias type="cn.itsource.domain.Dept" alias="Dept" />
<!-- 包的配置:项目中使用,添加了包之后,类名或类名首字母小写就是别名 -->
<package name="cn.itsource.domain" />
</typeAliases>
7.3.#与$区别
7.3.1.#{OGNL表达式}
MyBatis会把这个表达式使用?(占位符)替换,作为一个sql参数使用:推荐使用。比如name的值为:
定义SQL: select * from t_user where name = #{name}
最终SQL: select * from t_user where name = ?
7.3.2.${OGNL表达式}
1.MyBatis会把这个表达式的值替换到sql中,作为sql的组成部分。把获取到值直接拼接到SQL中;
2.如果sql中使用${OGNL},并且参数的类型是(integer、string…)那么OGNL表达式可以写成任意形式;
7.3.3.${OGNL}表达式的应用场景
1.不能用在登录,会出现sql注入
比如登录功能,在输入name的时候可以人为的制造成功:
User user=new User();
user.setName("\"admin\" or \"1=1\" ");
user.setPassword("\"admin\" ");
定义SQL: select id,name,password from t_user where name = ${name} and password=${password}
最终SQL: select id,name,password from t_user where name="test" or "1=1" and password="test" 出现sql注入
2.用在order by + limit的场景
注意:除了要拼接sql结构体要用$(是直接拼接sql),其他都用#,因为用#会替换为?,最终通过PreparedStament来设置参数,不会有sql注入问题;
8.课程总结
8.1.重点
1.Mybatis入门
2.Mybatis的CRUD操作
3.Mybatis使用细节
8.2.难点
1.Mybatis使用细节
2.定位错误
8.3.如何掌握
1.勤加练习
2.学会看说明手册
8.4.排错技巧(技巧)
9.常见问题
1.没有导入数据库的驱动包;
2.在XML中很多都是字符串,细心,不要写错;
3.在映射文件中全限定名可能会写错;
4.找不到相应的Statement(sql语句)
(1)找SQL的Statement写错了;
(2)在核心XML中没有找相应的映射文件;
5.在我们调用Statement(sql语句的时候),经常会忘记传参;
6.执行成功后,数据库却没有反映,很有可能是没有提交事务;
7.可能我们忘了写执行的代码了;
8.错误一定要打印出来(执行的时候没效果,但是又不报错);
9.Mapper中就算一个语句没有使用,它的错也可能会影响到其它正确的语句;
10.框架的错往往从后向前找;
11.很多同学没有取别名,但是他一直去用;
12.字符编码:useUnicode=true&characterEncoding=UTF-8
10.课后练习
1.课堂代码1-2遍;
11.面试题
1.Mybatis和Jdbc联系和区别; (预计10分钟完成)
2.Mybatis和Jpa实现框架Hibernate区分和联系; (预计10分钟完成)
12.扩展知识或课外阅读推荐(可选)
12.1.扩展知识
Mybatis与Hibernate区别?
1.Hibernate
(1)优点:对于简单的CRUD可以不写SQL语句,代码可移植(可以更换不同的数据库);
(2)缺点:
①Hibernate不够灵活,对于复杂的SQL支持较弱;
②HQL黑箱操作,调优复杂度高;
③不适合大型互联网项目的高性能要求;
2.Mybatis
(1)优点:高度灵活,自己操作SQL,方便优化。学习门槛低,易于维护和开发;
(2)缺点:由于每种数据库的SQL语句是不一样的,所以代码不可移植;