关注“Java 后端技术全栈”
回复“面试”获取全套面试材料
本文次要内容:
传统 JDBC
传统 JDBC 编码格局
`public class DataBaseUtil {`
`public static final String URL = "jdbc:mysql://localhost:3306/mblog";`
`public static final String USER = "root";`
`public static final String PASSWORD = "123456";`
`public static void main(String[] args) throws Exception {`
`Class.forName("com.mysql.jdbc.Driver");`
`//2.`
`Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);`
`//3.`
`Statement stmt = conn.createStatement();`
`//4.`
`ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1");`
`// 如果有数据,rs.next()返回 true`
`while(rs.next()){`
`System.out.println("name:"+rs.getString("name")+"年龄:"+rs.getInt("age"));`
`}`
`}`
`}`
下面代码中常识为了展现 JDBC 整个过程(异样和资源是简略粗犷的解决了,咱们关注的点不在这两个)。
大抵能够分为六个步骤:
- 加载驱动程序
- 取得数据库连贯
- 创立一个 Statement 对象
- 操作数据库,实现增删改查
- 获取后果集
- 敞开资源
从应用层面来说,采纳原生态的 JDBC 在我的项目中应用起来老本还是很高的。如果咱们的我的项目中的业务绝对比较复杂,数据库表也绝对较多,各种操作数据库的增删改查的办法也会随之多起来,那么这样的代码反复次数会十分之多。
传统 JDBC 的问题
- 创立数据库的连贯存在大量的硬编码,
- 执行 statement 时存在硬编码.
- 频繁的开启和敞开数据库连贯, 会重大影响数据库的性能, 节约数据库的资源.
- 存在大量的重复性编码
为了解决以上问题,就诞生了各种各样替换 JDBC
的产品。即就是 ORM 框架。
什么是 ORM?
全称为 Object Relational Mapping。对象 - 映射 - 关系型数据库。对象关系映射(,简称 ORM,或 O /RM,或 O /R mapping),用于实现面向对象编程语言里不同类型零碎的数据之间的转换。简略的说,ORM 是通过应用形容对象和数据库之间映射的元数据,将程序中的对象与关系数据库互相映射。
ORM 提供了实现长久化层的另一种模式,它采纳映射元数据来形容对象关系的映射,使得 ORM 中间件能在任何一个利用的业务逻辑层和数据库层之间充当桥梁。
咱们的我的项目中是这样的:
比如说:Apache DbUtils、Spring JDBC、Hibernate、Ibatis
(Mybatis
的前生)、Spring Data Jpa
等等。
目前最为风行的 Mybatis
和Spring Data Jpa
。本系列咱们先解说 Mybatis
,Jpa
前面再讲。
ORM 的优缺点
长处1. 进步了开发效率。因为 ORM 能够主动对 Entity 对象与数据库中的 Table 进行字段与属性的映射,所以咱们理论可能曾经不须要一个专用的、宏大的数据拜访层。2.ORM 提供了对数据库的映射,不必 sql 间接编码,可能像操作对象一样从数据库获取数据。
毛病 就义程序的执行效率和会固定思维模式,升高了开发的灵活性。
从系统结构上来看, 采纳 ORM 的零碎个别都是多层零碎,零碎的档次多了,效率就会升高。ORM 是一种齐全的面向对象的做法,而面向对象的做法也会对性能产生肯定的影响。在咱们开发零碎时,个别都有性能问题。性能问题次要产生在算法不正确和与数据库不正确的应用上。ORM 所生成的代码个别不太可能写出很高效的算法,在数据库利用上更有可能会被误用,次要体现在对长久对象的提取和和数据的加工解决上,如果用上了 ORM, 程序员很有可能将全副的数据提取到内存对象中,而后再进行过滤和加工解决,这样就容易产生性能问题。在对对象做长久化时,ORM 个别会长久化所有的属性,有时,这是不心愿的。但 ORM 是一种工具,工具的确能解决一些反复,简略的劳动。这是不可否认的。但咱们不能指望工具能一劳永逸的解决所有问题,有些问题还是须要非凡解决的,但须要非凡解决的局部对绝大多数的零碎,应该是很少的。
MyBatis 是什么?
如果在面试的时候被问到,只有你说出上面三种即可。
MyBatis 是一款优良的长久层框架,它反对自定义 SQL、存储过程以及高级映射。
MyBatis 罢黜了简直所有的 JDBC 代码以及设置参数和获取后果集的工作。
MyBatis 能够通过简略的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,一般老式 Java 对象)为数据库中的记录。
来自官网。
MyBatis 的长处和毛病
长处:
(1)基于 SQL 语句编程,相当灵便,不会对应用程序或者数据库的现有设计造成任何影响,SQL 写在 XML 里,解除 sql 与程序代码的耦合,便于对立治理;提供 XML 标签,反对编写动静 SQL 语句,并可重用。
(2)与 JDBC 相比,缩小了 50% 以上的代码量,打消了 JDBC 大量冗余的代码,不须要手动开关连贯;
(3)很好的与各种数据库兼容(因为 MyBatis 应用 JDBC 来连贯数据库,所以只有 JDBC 反对的数据库 MyBatis 都反对)。
(4)可能与 Spring 很好的集成;
(5)提供映射标签,反对对象与数据库的 ORM 字段关系映射;提供对象关系映射标签,反对对象关系组件保护。
毛病
(1)SQL 语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写 SQL 语句的功底有肯定要求。
(2)SQL 语句依赖于数据库,导致数据库移植性差,不能随便更换数据库。
Mybatis
环境搭建及简略实例
创立一张数据库表
创立一张 m\_user 表应用 MySQL
数据库。
``CREATE TABLE `m_user` (``
`` `id` int(11) NOT NULL AUTO_INCREMENT,``
`` `name` varchar(255) DEFAULT NULL,``
`` `age` int(11) DEFAULT NULL,``
``PRIMARY KEY (`id`)``
`) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`
增加依赖
`<dependency>`
`<groupId>org.mybatis</groupId>`
`<artifactId>mybatis</artifactId>`
`<version>3.5.2</version>`
`</dependency>`
`<dependency>`
`<groupId>mysql</groupId>`
`<artifactId>mysql-connector-java</artifactId>`
`<version>8.0.16</version>`
`<scope>runtime</scope>`
`</dependency>`
`</dependencies>`
我的项目构造如下:
创立一个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">`
`<configuration>`
`<environments default="development">`
`<environment id="development">`
`<transactionManager type="JDBC"/>`
`<dataSource type="POOLED">`
`<property name="driver" value="com.mysql.cj.jdbc.Driver"/>`
`<property name="url" value="jdbc:mysql://localhost:3306/mblog?useUnicode=true"/>`
`<property name="username" value="root"/>`
`<property name="password" value="123456"/>`
`</dataSource>`
`</environment>`
`</environments>`
`<mappers>`
`<mapper resource="mapper/UserMapper.xml"/>`
`</mappers>`
`</configuration>`
实体类 User
`ublic class User {`
`private Integer id;`
`private String name;`
`private Integer age;`
`//set get`
`@Override`
`public String toString() {`
`return "User{" +`
`"id=" + id +`
`", name='" + name + '\'' +`
`", age=" + age +`
`'}';`
`}`
`}`
创立UserMapper.java
`import com.tian.mybatis.entity.User;`
`public interface UserMapper {`
`User selectUserById(Integer id);`
`}`
创立UserMapper.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="com.tian.mybatis.mapper.UserMapper">`
`<select id="selectUserById" resultType="com.tian.mybatis.entity.User">`
`select * from m_user where id = #{id}`
`</select>`
`</mapper>`
创立一个测试类
`import com.tian.mybatis.entity.User;`
`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.IOException;`
`import java.io.InputStream;`
`public class MybatisApplication {`
`public static void main(String[] args) {`
`String resource = "mybatis-config.xml";`
`InputStream inputStream = null;`
`SqlSession sqlSession =null;`
`try {`
`inputStream = Resources.getResourceAsStream(resource);`
`// 工厂模式 `
`SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);`
`//sql 操作会话 `
`sqlSession = sqlSessionFactory.openSession();`
`// 获取数据并解析成 User 对象 `
`User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1);`
`System.out.println(user);`
`} catch (Exception e) {`
`e.printStackTrace();`
`}finally {`
`try {`
`inputStream.close();`
`} catch (IOException e) {`
`e.printStackTrace();`
`}`
`sqlSession.close();`
`}`
`}`
`}`
输入后果:
`User{id=1, name='tian', age=22}`
整体步骤:
另外一种启动形式
`import com.tian.mybatis.entity.User;`
`import org.apache.ibatis.builder.xml.XMLConfigBuilder;`
`import org.apache.ibatis.io.Resources;`
`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 org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;`
`import java.io.IOException;`
`import java.io.InputStream;`
`import java.util.Properties;`
`public class MybatisApplication {`
`public static void main(String[] args) {`
`String resource = "mybatis-config.xml";`
`InputStream inputStream = null;`
`try {`
`inputStream = Resources.getResourceAsStream(resource);`
`} catch (IOException e) {`
`e.printStackTrace();`
`}`
`// 解析 xml 文件 `
`XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null, null);`
`// 构建一个 SqlSessionFactory 工厂类 `
`SqlSessionFactory sqlSessionFactory = build(parser.parse());`
`// 创立一个 SqlSession`
`SqlSession sqlSession = sqlSessionFactory.openSession();`
`// 获取数据并解析成 User 对象 `
`User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1);`
`System.out.println(user);`
`}`
`public static SqlSessionFactory build(Configuration config) {`
`return new DefaultSqlSessionFactory(config);`
`}`
`}`
输入和下面一样。还能够间接应用 Java 代码而不必mybatis-config.xml
。
`// 创立数据源 `
`DataSource dataSource = getDataSource();`
`TransactionFactory transactionFactory = new JdbcTransactionFactory();`
`Environment environment = new Environment("development", transactionFactory, dataSource);`
`Configuration configuration = new Configuration(environment);`
`configuration.addMapper(BlogMapper.class);`
`SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);`
小总结
从下面这个案例中咱们大抵能猜到,Mybatis 中最次要几个组件:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
Mapper
SqlSessionFactoryBuilder
这个类能够被初始、应用和抛弃,如果你曾经创立好了一个 SqlSessionFactory
后就不必再保留它。因而,SqlSessionFactoryBuilder
的最好作用域是办法体内,比如说定义一个办法变量。
你能够重复使用SqlSessionFactoryBuilder
生成多个 SqlSessionFactory
实例,然而最好不要强行保留,因为 XML 的解析资源要用来做其它更重要的事。
SqlSessionFactory
一旦创立,SqlSessionFactory
就会在整个利用过程中始终存在。所以没有理由去销毁和再创立它,一个 利用运行中也不倡议屡次创立 SqlSessionFactory。如果真的那样做,会显得很高明。
因而 SqlSessionFactory 最好的作用域是 Application。能够有多种办法实现。最简略的办法是单例模式或者是动态单例模式。然而这既不是宽泛赞成和好用的。反而,应用 Google Guice 或 Spring 来进行依赖反射会更好。这些框架允 许你生成管理器来治理 SqlSessionFactory
的单例生命周期
SqlSession
每个线程都有本人的 SqlSession 实例,SqlSession 实例是不能被共享,也是不是线程平安的。因而最好 应用 Request 作用域或者办法体作用域。
不要应用类的动态变量来援用一个 SqlSession 实例,甚至不要应用类的一个实例变更来援用。永远不要在一个被治理域中援用 SqlSession,比如说在 Servlet 中的 HttpSession 中。如果你正在应用 WEB 框架,应该让 SqlSession 追随 HTTP 申请的类似作用域。
也就是说,在收到一个 HTTP 申请过后,关上 SqlSession,等返回一个回应当前,立马关掉这个 SqlSession。敞开 SqlSession 是十分重要的。你必须要确保 SqlSession 在 finally 办法体中失常敞开。
`SqlSession session = sqlSessionFactory.openSession();`
`try {`
`// do work`
`} finally {`
`session.close();`
`}`
应用这种模式来贯通你的所有代码,以确保所有数据库资源都被齐全敞开。
Mapper
Mapper 是一种你创立的用于绑定映射语句的接口。Mapper 接口的实例是用 SqlSession 来取得的。同样,从技术上来说,最宽泛的 Mapper 实例作用域像 SqlSession 一样,应用申请作用域。确切地说,在办法 被调用的时候调用 Mapper 实例,而后应用后,就主动销毁掉。不须要应用明确的登记。当一个申请执 行正确无误的时候,像 SqlSession 一样,你能够轻而易举地操控这所有。放弃简略性,放弃 Mapper 在 办法体作用域内。
`// 获取数据并解析成 User 对象 `
`User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1);`
`System.out.println(user);`
这里映射波及到四个主体:
- 实体类 User。
- 接口
UaerMapper
。 xml
配置文件UserMapper
。- 数据库表 m\_user
Mybatis 的五部曲:
总结
回顾 JDBC
的 demo,JDBC
中的问题,创立一个 Mybatis 示例,总结出重要的四个组件,以及每个组件的作用。
举荐浏览
《亿级流量网站架构核心技术》.pdf
《算法的乐趣》.pdf
面试官:Object 有些什么办法?教你如何吊打他