一、MyBatis
- mybatis的介绍
- MyBatis 支持普通SQL查询,存储过程和高级映射的优秀持久层框架。
- MyBatis 消除了几乎所有的JDBC代码和手工设置参数以及结果集的检索。
- MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
- MyBatis不能自动创建表,如果能够自动建表,必须自己先准备好建表的sql语句。
- mybatis和hibernate的区别:
- 两者都是目前流行的ORM框架
- hibernate是一个完整的ORM框架,常规CRUD我们不需要写一句SQL; 你表面上看到操作时非常简单,其实底层都是不简单的,它都是做了层层的封装,所以性能方面要比我们写原生sql性能要低的多
- MyBatis 并不是一个完整的ORM框架,因为我们还需要自己去写全部SQL,如果查询出来数据的列和对象中的 字段不一致,我们还得手动进行一个映射配置。
- ==ORM框架的操作数据库关系方式有很多种,常用的有两种 ==
- Sql操作方式(对jdbc进行封装)(mybatis的实现方式)
把SQL配置到配置文件中,通过不同SQL中完成对象实体和数据库关系相互转换的操作。 - 完整操作(JPA、Hibenate实现方式)
直接映射的是对象实体和数据库关系映射。操作数据库关系,不用写SQL由框架自己生成。
二、小试一下
- 步骤:
- 先创建一个普通的java项目
- 导入mybatis的核心包。
- 导入和mybatis的一些依赖包
- 导入数据库驱动包。所有操作数据库的框架底层都是JDBC
注意:这里导入MySql的驱动包
- 根据数据库表创建domain,domain中的字段必须和表中的字段一致。
注意mybatis是不会自动创建表的,分清与JPA的区别- domain类。
注意类型要一致
- 数据库
字段
类型
- domain类。
- mybatis的xml核心配置文件(四大金刚配置–在连接池中)
(1)准备好连接数据库的四大配置信息的properties文件jdbc.properties
(2)xml核心配置文件mybatis-config.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">
<!--根:XML必须要有一个根-->
<configuration>
<!--连接配置的数据库的配置文件-->
<properties resource="jdbc.properties" />
<!--
environments:环境们。以后要用数据库:生产环境,测试环境。
default:默认的。默认是哪个环境。
-->
<environments default="development">
<!--
environment:一个环境就代表一个数据库的连接信息
id:为这个环境取唯一一个id名称
-->
<environment id="development">
<!--
transactionManager:配置事务管理器
type=”[JDBC|MANAGED]”:事务管理器的类型,有两个
JDBC:使用JDBC的默认事务功能
MANAGED:这个配置几乎没做什么(没有事务)
-->
<transactionManager type="JDBC"></transactionManager>
<!--
dataSource:连接池(数据源) 肯定要写这四个数据库配置
type(POOLED):MyBatis自带的连接池。官方文档中还有很多,根据情况选
以后集成会改成:DBCP/C3P0
-->
<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代表的是相应的ORM映射文件:包括自己写的sql
-->
<mappers>
<mapper resource="cn/itsource/domain/ProductMapper.xml"/>
</mappers>
</configuration>
- 新建xml文件productMapper.xml,写入相应domain的SQL查询语句。文件名规范为DomainMapper.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">
<!--
namespece:命名空间
-->
<mapper namespace="cn.itsource.domain.ProductMapper">
<!--
select:查询
以后会写很多SQL语句,Java代码需要精确的找到某一条SQL
如何查找? namespece + id
cn.itsource.domain.ProductMapper.findOne
id:这条SQL的唯一名称
parameterType:传入的参数类型,有参数就写,没有参数就不写(long:大Long还是小long)
long:是大Long _long:小long
resultType:返回的(每一条数据)结果类型 -> 必需写全限定名称
-->
<!--需要传参数id,而id的类型是Long-->
<select id="findOne" parameterType="long" resultType="cn.itsource.domain.Product">
select * from product where id = #{id}
</select>
<!--查询所有数据,就不需要传参数-->
<select id="findAll" resultType="cn.itsource.domain.Product">
select * from product
</select>
</mapper>
- 图片清晰解释说明:
- 注意的规范
- 我们的映射文件一般情况下是和它对应的domain实体类在同一个层级
- 这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
- namespace命名空间的名称为了确定唯一性, 最好写成如下格式:XxxMapper
- 除了MyBatis支持的类型,其它的类型都通通使用全限定名
三、使用mybatis完成CRUD
- 仔细看上面测试类中的代码也就发现了很多的代码时重复的,所以我们这边抽个工具类出来。
抽工具类方式:静态方法、单例(饿汉和懒汉模式)、枚举
/*
* mybatis的工具类,与JPA的工具类相似
* */
public class MyBatisUtil {
private static SqlSessionFactory sessionFactory;
//静态代码块,类加载的时候就运行。(而且只会执行一次)
static {
try {
sessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
} catch (Exception e) {这里的异常用Exception大异常,不要用IO异常,否则很多错是不会报出来
e.printStackTrace();
}
}
//提供一个静态的方法,类可以直接调用
public static SqlSession getSession(){
//直接返回一个SqlSession对象
return sessionFactory.openSession();
}
}
- 测试工具类是否能用
重点:增加、删除、修改操作是要添加事务的
MySQL中有多种引擎:INNODB(支持事务,支持外键,安全)、MyISAM(不支持事务,不支持外键,速度快)在数据库表中更改
将数据库表改成INNODB引擎,安全性高
- Dao层接口类准备
重点开始 - 查询一条数据操作
- 在ProductMapper.xml中写好sql语句
- 在dao层的实现类ProductDaoImpl中写实现方法
- 测试类
- 查询到所有数据
- 在ProductMapper.xml中写好sql语句
- 在dao层的实现类ProductDaoImpl中写实现方法
- 测试
- 增加保存方法
- 在ProductMapper.xml中写好sql语句
- 在ProductMapper.xml中写好sql语句
- 在dao层的实现类ProductDaoImpl中写实现方法
- 测试
- 删除方法
- 在ProductMapper.xml中写好sql语句
- 在dao层的实现类ProductDaoImpl中写实现方法
- 测试
- 修改操作
- 在ProductMapper.xml中写好sql语句
- 在dao层的实现类ProductDaoImpl中写实现方法
- 测试类
三、MyBatis三大核心对象
- SqlSessionFactoryBulider、—>创建SqlSessionFactory、—>创建SqlSession
- SqlSessionFactoryBulider:解析xml配置文件,创建SqlSessionFactory后就没用了
- SqlSessionFactory:重量级对象(连接池、二级缓存,一个项目一个就可了,不能随意创建和随意销毁,线程安全。简单的使用就是单例模式或静态单例模式)
- SqlSession:轻量级对象(一级缓存,线程不安全,每一个线程创建一次,都有一个实例)
四、mybatis细节部分
- 添加时拿到返回的主键。(拿到刚添加的数据的主键)
- 在XxxMapper.xml中的添加的sql语句中加上几个属性就可以:
- 效果图:
- Log4j日志框架 。直接拷贝使用
- 在resources中创建一个日志的配置文件:log4j.properties 名字不能随意取
# 全局:你要打印的东西:只打印错误
log4j.rootLogger=ERROR, stdout
#log4j.rootLogger=NONE 不要日志就用NONE
#把左边包名改成你自己的包名
#局部要求 ERROR:错误 Warn:警告 Info:信息 Debug:调试 TRACE:详细
log4j.logger.cn.itsource=TRACE
#代表的是打印的位置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#打印的格式(可以灵活地指定布局模式)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#这里就是自定义的格式 %d:时间 %p:级别
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
- 测试
- 打印出来
- MyBatis中为一个类取别名
- 别名分为两种:
第一种:内置别名
第二种:自定义别名
之前传参与接收结果,都是使用的全限定名。如何让自己写的类使用别名?
注:必需在主文件中(就是配置的mybatis的核心xml配置文件)设置别名,其它地方才可以使用(切记切记)
(1)只给一个domain类设置别名
配置一个domain类的别名
- 然后就可以在相应的XxxMapper.xml的sql语句配置文件中将自己类换成取好的别名
(2)以后开发肯定会有很多的domain类,所以设置一个domain类的别名肯定不行。
所以给domain这个包设置别名
直接在主文件中(就是配置的mybatis的核心xml配置文件)设置包的别名
- 这样也可以使用别名
- 列名与属性名不对应的解决方案resultMap
比如说:数据库表中的关联字段是dir_id,而在根据数据库表生成的domain类中这个字段自动就变成了dirId,驼峰式的字段了,打印的时候就获取不到数据库中dir_id的值。如何处理?
一种方式:要么就将数据库中的dirId字段改为数据库的dir_id,一致。比较麻烦。
另一种方式:这个时候就要告诉MyBatis,我们需要把哪些列名与属性名对应上。将javaBean自动映射,改为使用手动映射就可以解决这个问题
- 在XxxMapper.xml自己手动写sql的配置文件中配置手动映射
- 然后可以将原来的自动映射的sql语句改为手动映射
将原来的自动映射resultType改为设置的手动映射resultMap=手动映射的id,如下:
- 关于#符号和$符号
- sql的xml文件中的#和$的区别:
(1) $:要求必须传对象过来,它里面拿的是对象的属性。#随便都可以
(2)#是占位符的方式(预编译方式:性能更好,更安全,防止sql注入), $ 是直接拼接的字符串。
(3)以后能用#号就用#号,如果有#号搞不定的就拼接字符串
要使用 $符号。先随便准备一个对象
那么使用sql时就应该这样写:
在XxxMapper.xml配置中的sql语句
- 测试
三、报错
- java.lang.ClassNotFoundException: org.hamcrest.SelfDescribing
- 原因:junit测试的版本过高了,原来的是junit 4.1.2 版本,换个其他的低点的版本
2.Mappend statemens collection does not conain value for…t