##面向对象的世界与关系数据库的鸿沟 Java语言是一门面向对象的程序设计语言,面向对象是从软件工程的基本原则高内聚低耦合等理论基础上发展起来的。
- 面向对象的世界中数据都是以对象的形式存在的。
- 关系型数据库基于数学理论发展起来的,在关系型数据库中数据是以行、列二元表。
正式编程语言与数据库的不匹配,我们没有办法在Java程序中像操作对象一样的方式去操作关系型数据库当中的数据。才需要一个中间的映射技术,帮助我们自动的实现对象与二元表之间的转换。这种对象关系数据库映射技术应运而生。
##ORM
- ORM(Object / Relation Mapping) 能够帮助我们建立对象到数据库表之间的映射关系,让我们对对象的操作自动转换成关系数据库的操作,对于开发用户来说,在Java程序中就可以像直接操作修改
- 持久化类与数据库表之间的映射关系
- 对持久化对象的操作自动转换成对关系数据库操作
- 关系数据库的每一行映射数据库记录,通过中间映射技术,自动的为Java对象
- 关系数据库的每一列映射为Java对象的每个属性
#MyBatis
在2010年这个项目由Apache基金会迁移到了Google Code并改名为MyBatis。目前MyBatis在企业开发中应用非常广泛。本质上是ORM框架,但是与传统ORM框架显著不同的是,并非建立Java对象到关系型数据库表数据之间的映射关系。而是建立,对对象的操作方法到SQL语句之间的映射关系。由于SQL语句本身是需要由SQL语句来编写的。所以MyBatis的优势是可以让开发者使用关系型数据库的所有的特性。比如存储过程、视图、复杂查询等等。同时由于MyBatis也让开发者对执行的SQL获得了更多的控制,所以开发者可以编写更加高效率的SQL语句,来提高应用程序对数据库的访问效率。MyBatis是通过XML文件定义后端数据库的,配置Java方法与后端映射关系的。
- 项目前身是Apache基金会下的一个开源项目iBatis
- 支持自定义SQL、存储过程和高级映射的持久化框架
- 使用XML或者注解配置
- 能够映射基本数据元素、接口、Java对象到数据库
##MyBatis功能架构 MyBatis功能架构有三层, ###接口层 第一层是接口层,提供给外部使用的API接口。提供给我们程序开发人员,开发人员使用本地API来操作数据库,接口层接到调用请求后,将会把请求转发给数据处理层进行执行。 ###数据库处理层 第二层是数据处理层,主要负责具体SQL的查找、SQL解析、SQL执行和执行结果结果的映射处理。主要目的是根据调用请求来完成一次数据库操作 ###基础支持层 最后一层是基础支撑层,主要负责最基础的数据支持,数据库的连接管理、事务管理、配置加载、缓存处理。都是共用的功能,把这些功能抽象出来作为最基础的组件。给上层的数据库处理层提供最基础的支撑。
##MyBatis工作流机制 首先我们需要在应用程序启动的时候,加载XML文件。该XML文件定义了后端数据库的地址,同时也定义了SQL与Java方法之间的映射关系
- 根据XML或者注解加载SQL语句、参数映射、结果映射到内存
- 应用程序调用API传入参数和SQL ID
- MyBatis自动生成SQL语句完成数据库访问,转换执行结果为Java对象,返回应用程序
##MyBatis环境搭建
首先我们需要下载MyBatis,解压缩后查看目录树如下mybatis/└── mybatis-3.4.1 ├── LICENSE ├── NOTICE ├── lib │ ├── ant-1.9.6.jar │ ├── ant-launcher-1.9.6.jar │ ├── asm-5.0.4.jar │ ├── cglib-3.2.2.jar │ ├── commons-logging-1.2.jar │ ├── javassist-3.20.0-GA.jar │ ├── log4j-1.2.17.jar │ ├── log4j-api-2.3.jar │ ├── log4j-core-2.3.jar │ ├── ognl-3.1.8.jar │ ├── slf4j-api-1.7.21.jar │ └── slf4j-log4j12-1.7.21.jar ├── mybatis-3.4.1.jar └── mybatis-3.4.1.pdf2 directories, 16 files
应用程序使用MyBatis需要把解压缩当中的mybatis-3.x.x.jar放置到lib目录下,更加推荐Maven方式,由于MyBatis同样基础JDBC来访问后端数据库的,所以我们同样需要对应数据库的JDBC驱动。
###Maven
org.mybatis mybatis 3.4.1
###Gradle
// https://mvnrepository.com/artifact/org.mybatis/mybatiscompile group: 'org.mybatis', name: 'mybatis', version: '3.4.1'
##SqlSessionFactory 每个MyBatis应用都是基于SqlSessionFactory实例为中心的。通过SqlSessionFactory实例可以获取,将对象操作转换成数据库SQL的Session。我们通过XML配置文件,可以完成SqlSessionFactory的配置。首先我们要来完成配置文件,整个XML配置文件包含了对MyBatis系统的核心配置。包括后端的数据库连接实例数据源,和决定事务范围事务处理的事务管理器。
###transactionManager 在transactionManager有type属性,提供了两个选项,jdbc和managed。
- jdbc jdbc表示MyBatis的事务控制,直接食用jdbc的提交和回滚。表示MyBatis依赖数据库源获取的数据库连接来管理事物的范围。实际上是依赖JDBC来实现事务控制的。
- managed managed表示MyBatis的事务提交和回滚MyBatis是不做任何事情,不会去调用JDBC的事务提交和回滚。事务的控制是交给外部的容器,例如Spring。
###dataSource 之后我们要配置后端的数据库源,与JDBC一致,主要包括4个属性。分别是数据库驱动、URL、用户名、密码。 ###官方文档SqlSessionFactory的配置
##Java对象 ###构造对象 在配置完毕MyBatis后,我们就需要对程序进行编写,由于MyBatis是Object Relation Mapping。我们要定义Java对象,然后建立对象和对象操作SQL语句之间的映射关系。我们定义的Java对象包括一些属性。我们这里以User对象作为示例。
package com.hava.mybatis.user.entity;/** * Created by zhanpeng on 09/10/2016. */public class User { private Integer id; private String userName; private String corp; //公司 public User(Integer id,String userName,String corp) { this.id = id; this.userName = userName; this.corp = corp; } //Getter and Setter public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getCorp() { return corp; } public void setCorp(String corp) { this.corp = corp; }}
###构建接口 有了Java对象以后,我们还需要定义对这个Java对象的操作。MyBatis与其他与其他传统ORM框架是不同的。不是直接建立对象和关系型数据库表数据的映射,而是采取更加灵活的方式,将对对象的操作与关系型数据库的SQL语句建立关系。所以我们需要定义一些对对象的操作。
我们使用Java里面的Interface接口的方式,来定义对对象的操作。package com.hava.mybatis.user.entity;/** * Created by zhanpeng on 09/10/2016. */public interface GetUserInfo { public User getUser(Integer id); public void addUser(User user); public void updateUser(User user); public void deleteUser(User user);}
##创建Java对象和SQL语句映射关系配置文件 Java对象接口与SQL语句的映射关系,映射关系也是通过配置文件来完成的。配置也是XML文件,配置文件中最重要的是包含Mapper的标签。 ###namespace 标签的namespace属性的值是指向Java对象接口操作类的位置。 ###定义SQL语句 获取数据库中的信息,检索数据库获取User信息,然后映射到Java的User对象中。所以我们这里的select id定义为getUser,对应接口的具体方法。然后parameterType定义int,由于我们的方法参数为int,resultType指向我们定义的Java的User类。希望MyBatis把返回的结果自动转化成定义为Java对象。注意加完整路径。
- 映射文件
##注册配置文件 我们还需要将这个映射文件,加载到注册到刚开始配置的SqlSessionFactory的配置文件中,我们要在之前的配置文件中增加mappers的标签。
##完成数据库查询 MyBatis完成数据库查询需要完成三个步骤,首先需要加载配置文件,然后创建一个SqlSessionFactory的实例。第二步通过SqlSessionFactory获取sqlSession对象,sqlSession能够帮助我们执行具体的SQL操作。最后一步就是利用Session进行查询。
##MyBatis查询实例 ###数据库初始化
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(100) NOT NULL, `corp` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
手动添加了数据 ###修改pom.xml以支持xml运行
src/main/java **/*.xml
###mybatis-conf.xml 上面的例子并没有添加mybatis的DOCTYPE定义
###执行查询过程
package com.hava.mybatis.user.service;import com.hava.mybatis.user.entity.GetUserInfo;import com.hava.mybatis.user.entity.User;import org.apache.ibatis.session.Configuration;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;/** * Created by zhanpeng on 09/10/2016. */public class HelloMyBatis { public static void main(String [] args) { //1.声明MyBatis的配置文件目录 String resource = "mybatis-conf.xml"; //2.加载应用程序配置文件 InputStream inputStream = HelloMyBatis.class.getClassLoader().getResourceAsStream(resource); //3.创建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); Configuration configuration = sqlSessionFactory.getConfiguration(); //Exception in thread "main" org.apache.ibatis.binding.BindingException: Type interface com.hava.mybatis.user.entity.GetUserInfo is already known to the MapperRegistry.// configuration.addMapper(GetUserInfo.class); //4.获取Session SqlSession sqlSession = sqlSessionFactory.openSession(); try { //5.获取操作类 GetUserInfo getUserInfo = sqlSession.getMapper(GetUserInfo.class); //6.完成查询操作 User user = getUserInfo.getUser(1); System.out.println("[user.getUserName]:" + user.getUserName()); } finally { //7.关闭session sqlSession.close(); } }}
###注意 在执行演示语句发生异常
Exception in thread "main" org.apache.ibatis.binding.BindingException: Type interface com.hava.mybatis.user.entity.GetUserInfo is already known to the MapperRegistry.// configuration.addMapper(GetUserInfo.class);
说明如果在配置文件当中,已经mapper了接口文件,则不需要在代码中再次mapper。 ###执行结果
[user.getUserName]:ZhangSanProcess finished with exit code 0
#MyBatis优势与劣势
- 优势
-
- 入门门槛比较低
-
- 更加灵活,SQL优化 SQL语句自己编写,来提高工作效率
- 劣势
-
- 需要自己编写SQL,工作量大
-
- 数据库移植性差
#通过注解的方式
- 映射文件通过注解的方式声明
package com.hava.mybatis.user.repository;import com.hava.mybatis.user.entity.User;import org.apache.ibatis.annotations.Select;/** * Created by zhanpeng on 09/10/2016. */public interface GetUserInfoAnnotation { @Select("select * from user where id = #{id}") public User getUser(int id);}
变更主程序
//1.声明MyBatis的配置文件目录 String resource = "mybatis-conf.xml"; //2.加载应用程序配置文件 InputStream inputStream = HelloMyBatis.class.getClassLoader().getResourceAsStream(resource); //3.创建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); Configuration configuration = sqlSessionFactory.getConfiguration(); //Exception in thread "main" org.apache.ibatis.binding.BindingException: Type interface com.hava.mybatis.user.entity.GetUserInfo is already known to the MapperRegistry. configuration.addMapper(GetUserInfoAnnotation.class); //4.获取Session SqlSession sqlSession = sqlSessionFactory.openSession(); try { //5.获取操作类// GetUserInfo getUserInfo = sqlSession.getMapper(GetUserInfo.class); //使用注解的方式 GetUserInfoAnnotation getUserInfo = sqlSession.getMapper(GetUserInfoAnnotation.class); //6.完成查询操作 User user = getUserInfo.getUser(1); System.out.println("[user.getUserName]:" + user.getUserName()); } finally { //7.关闭session sqlSession.close(); }
##其他数据库操作
- 增加
- 修改
- 删除
我们在openSession添加了true,是由于jdbc默认是以事务进行提交。但是在MyBatis是不一致的,默认会开启事务。如果不设置true,都是以事务的形式提交。
###定义正删改查接口
package com.hava.mybatis.user.repository;import com.hava.mybatis.user.entity.User;/** * Created by zhanpeng on 09/10/2016. */public interface UserOp { public void addUser(User user); public void updateUser(User user); public void deleteUser(int id); public User getUser(int id);}
###添加定义文件 insert通过useGeneratedKeys获取自增id号
insert into user (userName,corp) value(#{userName},#{corp}) update user set userName = #{userName} , corp = #{corp} where id = #{id} delete from user where id = #{id}
###修改Entity定义
public User(Integer id,String userName,String corp)public User(String userName,String corp)
必须均存在,用于MyBatis扫描和设置对象的属性,得知MyBatis并不是通过getter setter对对象的值进行设置。
package com.hava.mybatis.user.entity;/** * Created by zhanpeng on 09/10/2016. */public class User { private Integer id; private String userName; private String corp; public User(Integer id,String userName,String corp) { this.id = id; this.userName = userName; this.corp = corp; } public User(String userName,String corp) { this.userName = userName; this.corp = corp; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getCorp() { return corp; } public void setCorp(String corp) { this.corp = corp; }}
###执行函数
package com.hava.mybatis.user.service;import com.hava.mybatis.user.entity.User;import com.hava.mybatis.user.repository.GetUserInfoAnnotation;import com.hava.mybatis.user.repository.UserOp;import org.apache.ibatis.session.Configuration;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;/** * Created by zhanpeng on 09/10/2016. */public class HelloMyBatisMoreOp { public static void main(String[] args) { moreOp(); } public static void moreOp() { // 1. 声明配置⽂件 String resource = "mybatis-conf.xml"; // 2. 加载应⽤配置⽂件 InputStream is = HelloMyBatisMoreOp.class.getClassLoader() .getResourceAsStream(resource); // 3. 创建SqlSessonFactory SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder() .build(is); SqlSession session = sessionFactory.openSession(true); try { // 5. 获取操作类 UserOp userOp = session.getMapper(UserOp.class); User user = new User("XiaoMing", "Netease"); // 插⼊⽤户 userOp.addUser(user); System.out.println(user.getId()); // 查询⽤户 user = userOp.getUser(user.getId()); System.out.println("userId:" + user.getId() + ", userName:" + user.getUserName() + ", corp:" + user.getCorp()); user.setUserName("LiMing"); // 更新⽤户 userOp.updateUser(user); // 删除⽤户 userOp.deleteUser(user.getId()); } finally { // 7.关闭Session session.close(); } }}
###执行结果
4userId:4, userName:XiaoMing, corp:NeteaseProcess finished with exit code 0
###MyBatis的事务 如果openSession(true)则会自动提交sql,不会发生事务处理。如果采用默认方式openSession()
,则会开启事务,进行处理,如果开启事务,则需要手动进行提交工作。session.commit()
123