一、传统JDBC
在有Mybatis之前,我们都是怎么访问数据库的呢,是通过JDBC,那么JDBC是如何访问的呢,首先引入数据库连接jar包:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector-java.version}</version> </dependency>
然后书写代码进行链接访问,代码如下:
public class DbUtil { /* * 打开数据库 */ private static String driver;//连接数据库的驱动 private static String url; private static String username; private static String password; static { driver = "com.mysql.jdbc.Driver";//需要的数据库驱动 url = "jdbc:mysql://localhost:3306/test";//数据库名路径 username = "root"; password = "********"; } public static Connection open() { try { Class.forName(driver); return (Connection) DriverManager.getConnection(url, username, password); } catch (Exception e) { System.out.println("数据库连接失败!"); e.printStackTrace(); }//加载驱动 return null; } /* * 关闭数据库 */ public static void close(Connection conn) { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
访问如下:
public static void main(String[] args) { insert("Test", 18); } static void insert(String name, int age) { String sql = "insert into user(username,age) value(?,?)"; Connection conn = DbUtil.open(); try { PreparedStatement pstmt = (PreparedStatement) conn.prepareStatement(sql); pstmt.setString(1, name); pstmt.setInt(2, age); pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DbUtil.close(conn); } }
那么这样写有什么问题呢?
- jdbc底层没有用连接池、操作数据库需要频繁的创建和关联链接。消耗很大的资源;
- 写原生的jdbc代码在java中,一旦我们要修改sql的话,java需要整体编译,不利于系统维护;
- 使用PreparedStatement预编译的话对变量进行设置123数字,这样的序号不利于维护;
- 返回result结果集也需要硬编码。
因此就诞生了一些Mybatis、Hibernate框架,由于Hibernate框架很重,且SQL没有那么灵活,因此现在大量已被淘汰,那么我们接下来就讲讲Mybatis,Mybatis前身叫Ibatis。
二、什么是Mybatis
MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use simple XML or Annotations for configuration and map primitives, Map interfaces and Java POJOs (Plain Old Java Objects) to database records.
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
三、Mybatis快速开始
首先附上快速启动官网地址:http://www.mybatis.org/mybatis-3/zh/getting-started.html
1、包依赖
首先我们先用Maven引入mybatis的包,本文示例为:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.4</version> </dependency>
2、从 XML 中构建 SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。配置文件如下所示:
<?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> <properties resource="config.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mybatis/UserMapper.xml"/> </mappers> </configuration>
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test username=root password=********
其配置项说明如下:
其中,事务管理器(transactionManager)类型有两种:
- JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
- MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 J2EE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
其中,数据源(dataSource)类型有三种:
- UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
- POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
- JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
其配置目录结构如下图所示:
3、从 SqlSessionFactory 中获取 SqlSession
有了 SqlSessionFactory,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
SqlSession session = sqlSessionFactory.openSession(); try { User user = session.selectOne("org.mybatis.example.UserMapper.selectUser", 1); System.out.println("user:{}"+user); } finally { session.close(); }
完整的一个测试用例如下:
public class AppTest { @Test public void test() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); try { User user = session.selectOne("org.mybatis.example.UserMapper.selectUser", 1); System.out.println("user:{}"+user); } finally { session.close(); } } }
4、SQL语句映射
SQL语句既可以通过 XML 定义,也可以通过注解定义。我们看看 XML 定义语句的方式,事实上 MyBatis 提供的所有特性都可以利用基于 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="org.mybatis.example.UserMapper"> <select id="selectUser" resultType="com.houjing.mybatis.pojo.User"> select * from User where id = #{id} </select> </mapper>
执行测试用例,可以得到结果如下:
user:{}User{id=1, username='Monkey', age=18, phone='null', desc='null'}
因此一个基础的Mybatis就使用起来了。
5、注解实现SQL映射
除了使用XML映射方式外,还可以支持注解,使用注解时配置文件以及获取SqlSession是不一样的,首先配置文件如下:
<?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> <properties resource="config.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper class="com.houjing.mybatis.UserMapper"/> </mappers> </configuration>
此时也定义了个UserMapper.java的接口,内容如下:
public interface UserMapper { /* @Results({ @Result(property ="name",column = "username") })*/ @Select("select id,username as name,age,phone,`desc` from User where id = #{id}") public User selectUser(Integer id); }
如上所示,关于字段别名有两种写法,一种是@Result注解,一种是SQL语句中的as写法。
然后是SqlSession的获取以及使用,使用和指定语句的参数和返回值相匹配的接口(比如 UserMapper.class),例如:
try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.selectUser(1); }
6、注解以及XML配置方式优缺点
Annotaion方式:
- 不适合比较复杂的sql,比如关联查询;
- 不方便(收集)管理sql。
Xml方法:
- xml繁琐、麻烦,多了一个XML文件;
- 条件不确定的查询,如动态SQL、拼接SQL、包含逻辑判断的SQL;
- 容易出错写错,特殊字符转义。