静态代理
在运行之前,代理类与目标类之间的关系就已经产生了
MyBatis概述
MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google并更名为MyBatis,2013年迁移到GitHub。
MyBatis官网:https://github.com/mybatis
MyBatis对比Hibernate
Hibernate是“全自动”的ORM,MyBatis是“半自动”的ORM。
mybatis相比hibernate具有以下几个特点:
① 在XML文件中编写SQL语句,实现了SQL语句与代码的分离,为程序的维护带来便利
② 因为需要手动编写SQL语句,我们可以结合数据库的特点灵活控制SQL语句,因此能够实现比hibernate全自动的ORM框架更高的查询效率,能够完成复杂的查询
③ 简单,易于学习和使用,上手快
MyBatis体系结构
MyBatis工作原理
MyBatis主配置文件
mybatis主配置文件中主要配置:
1 数据库连接参数
2要注册的映射文件。注意:映射文件要放到最下面
主配置文件的各个元素以及各个元素常用的属性介绍 元素 元素的属性 对元素以及元素属性的说明 <properties> resource 当db.properties文件有多个的时候,只需要更改resource属性的值,复制db.properties文件名到resource属性中,一般情况下,db.properties文件连接数据库四要素写好是不直接在这里面更改的,而是更改该元素的属性的值 <environments> default 意思是在这个元素下可以有多个数据库连接的环境,比如oracle、mysql,也就是可有多个<environment>元素,default属性需要与其中一个<environment>元素的id属性值一致,表示默认使用的是哪个数据库连接环境 <environment> id 意思是给这个元素起名,表示数据库连接环境,需见名知意 <transactionManager> type type属性值有:
JDBC:表示事务管理默认JDBC的
<dataSource> type type属性值有:
POOLED:数据源采用的是mybatis自带的数据库连接池技术
<property> name
value
name:有固定的属性值,该属性值有driver、url、username、password。如果不知道去mybatis帮助文档可以查看到
value:
第1个name属性的value值
如果忘记怎么编写,在项目的Referenced Libraries目录下找到mysql-connector-java-x.x.xx-bin.jar > com.mysql.jdbc > Driver.class,右击
复制全名,去掉.class即可第2个name属性的value值
jdbc:mysql://127.0.0.1:3306/test,如果端口号3306没有更改,直接///,省略IP地址跟端口号,jdbc代表总协议,mysql代表子协议,跟http协议一样,包括电脑的任意文件目录,前面都有file://,只不过省略了
第3、4个name属性的value值省略
如果数据库连接四要素在db.properties文件中已经写好,value属性值写法是${db,properties文件的key值}<mappers> 要注册的映射文件 <mapper> resource 要注册的映射文件的路径,直接在项目路径下找到映射文件,右击复制即可
在主配置文件中,即使配置了dtd文件,也不会出现元素提示。可以将鼠标指针移动到根节点元素,按住F2键,如下图:
接下来根节点元素第一个子元素是<environments>,配好这个子元素以后还是报错的状态,移动到该元素上,F2键,提示这个子元素必须要有default属性,在根节点元素下还必须要有<environment>子元素,配置了这个子元素以后,还是报错的,同样,F2键,提示这个子元素必须要有id属性,在该子元素下必须要有<transactionManager>子元素和<dataSource>子元素。
关于元素后面的 (, + ? *) 的解释,以根节点元素<environments>举例:
MyBatis映射配置
映射文件的各个元素以及各个元素常用的属性介绍 元素 元素的属性 对元素以及元素属性的说明 <mapper> namespace 映射文件的根节点元素
namespace:映射文件的命名空间,必须配置,否则报错。同一包下的多个映射文件的namespace属性值不能相同
<insert> id
parameterType
插入语句元素
id:给这个<insert>起的名称。对应SqlSession的insert()的第一个参数
parameterType:要插入对象,包括类对象所在的包。对应SqlSession的insert()的第二个参数。sql语句示例:
insert into student(name,age,score)
values(#{name}, #{age}, #{score})
values括号的值是:要插入对象的属性名称,不是成员变量,底层用的是反射机制,会将values括号的每一个值会组装成getXxx(),获取要插入对象的成员变量的值
DAO层保存一个对象示例
代码结构以及代码如下:
Student类,省略get() set()
public class Student {
private Integer id;
private String name;
private int age;
private double score;
}
mapper.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="test">
<insert id="insertStudent" parameterType="net.csdn.entity.Student">
insert into student(name,age,score) values(#{name},#{age},#{score})
</insert>
</mapper>
mybatis.cfg.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">
<configuration>
<environments default="mysqlEnvironment">
<environment id="mysqlEnvironment">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///test" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="net/csdn/dao/mapper.xml" />
</mappers>
</configuration>
log4j.properties日志
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n
#debug级别,控制台就会打印sql语句。test是映射文件<mapper>元素的namespace属性值
log4j.logger.test=debug, console
StudentDao接口
public interface StudentDao {
public abstract void insertObj(Student student);
}
StudentDao接口实现类StudentDaoImpl
public class StudentDaoImpl implements StudentDao {
private SqlSession sqlSession;
@Override
public void insertObj(Student student) {
try {
//1 加载mybatis主配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis.cfg.xml");
//2 得到SqlSessionFactory对象。是线程安全的
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3 得到Session
sqlSession = sqlSessionFactory.openSession();
//4 持久化操作
sqlSession.insert("insertStudent", student); //insert(String statement, Object parameter); 方法的第一个参数是映射文件<insert>元素的id属性值,第二个参数是方法的形参
//5 提交事务
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(sqlSession != null){
sqlSession.close();
}
}
}
}
TestMybatis测试类。以保存为例
public class TestMybatis {
private StudentDao dao;
@Before
public void before(){
dao = new StudentDaoImpl();
}
@Test
public void test() {
Student student = new Student("张三三",25,77.5);
dao.insertObj(student);
}
}
执行test(),控制台打印如下:
查看数据库,插入成功!
接下来抽取工具类,在src下新建包:net.csdn.utils,新建如下类:
因为SqlSessionFactory一个应用程序只需要这一个对象,适合设计成单例模式,所以需要抽取出来。
public class SqlSessionFactoryUtils {
private static SqlSessionFactory sqlSessionFactory;
public SqlSessionFactoryUtils() {
}
public synchronized static SqlSession getSqlSession(){
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis.cfg.xml");
if (sqlSessionFactory == null) {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
return sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
在实现类StudentDaoImpl中,直接调用,直接省略1 2 3步骤,如下:
@Override
public void insertObj(Student student) {
sqlSession = SqlSessionFactoryUtils.getSqlSession();
//4 持久化操作
sqlSession.insert("insertStudent", student);
//5 提交事务
sqlSession.commit();
if(sqlSession != null){
sqlSession.close();
}
}
思考:在加载mybatis主配置文件的时候,为什么输入流没有关闭?
在输入流对象使用完毕后,不用手动进行流的关闭,因为 SqlSessionFactory对象的 build()会自动将输入流关闭。
鼠标移动到build()上,按住ctrl,点击Open Implementation,进入源码,如下:
SqlSession的方法解释:
提交 commit() 为什么是SqlSession提交的事物?
关闭 close() 只要SqlSession调用close(),就不需要调用SqlSession的rollback()
为什么调用了close()就不需要事物回滚了呢?
保存 insert(String statement, Object parameter) 第一个参数statement是映射文件<insert>元素的id属性的值,为什么是该元素的id属性的值?因为该元素编写了sql语句,还有要插入的值;如果同一包下有多个映射文件,<insert>元素的id属性的值又一样,需要在第一个参数的前面加上<mapper>元素的namespace属性值
第二个参数是要插入的对象的变量名称。
执行insert(),就会把第二个参数,要插入的对象传入到映射文件的<insert>元素当中,前提这个对象需要通过构造方法给成员变量赋值,不然带到<insert>元素下sql语句是空的。