Java之MyBatis入门详解
作者:MinggeQingchun
一、三层架构
Java中的三层架构指
1、界面层(User Interface layer;表示层,视图层):接受用户的数据,显示请求的处理结果。使用 web 页面或者手机 app和 用户交互
2、业务逻辑层(Business Logic Layer):接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据
3、数据访问层(Data access layer):与数据库打交道;主要实现对数据的增、删、改、查。将存储在数据库中的数据提交 给业务层,同时将业务层处理的数据保存到数据库
(1)三层对应的包
界面层: controller包 (servlet)
业务逻辑层: service 包(XXService类)
数据访问层: dao包(XXDao类)
(2)三层中类的交互
用户使用界面层----> 业务逻辑层----->数据访问层(持久层)---->数据库(MySQL,Oracle等)
(3)三层对应的处理框架
界面层---servlet---springmvc(框架)
业务逻辑层---service类--spring(框架)
数据访问层---dao类--mybatis(框架)
(4)使用三层架构有点
【1】结构清晰、耦合度低, 各层分工明确
【2】可维护性高,可扩展性高
【3】有利于标准化
【4】开发人员可以只关注整个结构中的其中某一层的功能实现
【5】有利于各层逻辑的复用
(5)缺点
【1】降低了系统的性能。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,三层架构必须通过中间层来完成
【2】导致级联的修改。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码
- 框架( Framework )是构成一类特定软件可复用设计的一组相互协作的类。框架规定了你的应用的体系结构。
- 它定义了整体结构,类和对象的分割,各部分的主要责任,类和对象怎么协作,以及控制流程。
- 框架预定义了这些设计参数,以便于应用设计者或实现者能集中精力于应用本身的特定细节
二、MyBatis
1、官方简介
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
java bean,pojo,vo,entity,domain可参考
2、百度基本信息
- MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由 apache software foundation 迁 移到了 google code,并且改名为 MyBatis 。
- 2013 年 11 月迁移到 Github。 iBATIS 一词来源于“internet”和“abatis”的组合,是一个基于 Java 的持久层框架。
- iBATIS 提供的 持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)
3、JDBC
JDBC代码如下
- (1)注册驱动
- (2)获取连接
- (3)获取数据库操作对象
- (4)执行SQL语句
- (5)处理查询结果集
- (6)释放资源
这些导致
- (1)代码比较多,开发效率低
- (2)需要关注 Connection ,Statement, ResultSet 对象创建和销毁
- (3)对 ResultSet 查询的结果,需要自己封装为 List
- (4)重复的代码比较多些
- (5)业务代码和数据库的操作混在一起
String driver = "com.mysql.cj.jdbc.Driver"; String url = "jdbc:mysql://127.0.0.1:3306/mydb"; String user = "root"; String pwd = "123456"; Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //1、注册驱动(连接的数据库) Class.forName(driver); //2、获取连接 conn = DriverManager.getConnection(url,user,pwd); //3、获取数据库操作对象(专门执行sql语句的对象) stmt = conn.createStatement(); //4、执行SQL语句(DQL DML....) String sql = "select empno,empname as name,sal from emp2 where empno=7369"; rs = stmt.executeQuery(sql); //5、处理查询结果集(只有当第四步执行的是select语句的时候,才有处理查询结果集) while (rs.next()){ /* (1)下标取值;下标从 1 开始 */ String empno = rs.getString(1); String empname = rs.getString(2); String sal = rs.getString(3); System.out.println(empno + " " + empname + " " + sal); /* (2)数据类型取值 */ int empno1 = rs.getInt(1); String empname1 = rs.getString(2); Double sal1 = rs.getDouble(3); System.out.println(empno1 + " " + empname1 + " " + sal1); /* (3)字段名取值 */ String empno2 = rs.getString("empno"); //如果执行的SQL语句中有别名,需要使用别名字段取值 String empname2 = rs.getString("name"); String sal2 = rs.getString("sal"); System.out.println(empno2 + " " + empname2 + " " + sal2); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); } finally { //6、释放资源;从小到大关闭 if (rs != null) { try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (stmt != null) { try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
MyBatis 是一个基于 java 的持久层ORM( Object Relational Mapping,对象关系映射)框架,内部封装了 jdbc,开发者只需要关注 sql 语句 本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。
MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的 动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回
mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
(1)sql mapper:sql映射
把数据库表中的一行数据 映射为 一个java对象
一行数据可以看做是一个java对象;操作这个对象,就相当于操作表中的数据
(2)Data Access Objects(DAOs):数据访问 , 对数据库执行增删改查
MyBatis框架
【1】提供了创建和销毁、关闭Connection ,Statement, ResultSet等对象能力
【2】提供了执行sql语句的能力
【3】提供了循环sql, 把sql的结果转为java对象, List集合的能力
三、MyBatis入门SqlSession
首先以SqlSession的方式使用mybatis框架
首先我们先设置一下maven的本地仓库
1、新建一个数据库,以及一张表user
CREATE TABLE `user` ( `user_id` int(10) NOT NULL COMMENT '用户名ID', `user_name` varchar(100) DEFAULT NULL COMMENT '用户名', `email` varchar(80) DEFAULT NULL COMMENT '用户邮箱', `age` int(5) DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、创建maven的普通Java工程,加入maven的mybatis坐标,mysql驱动坐标
其中,pom.xml文件如下
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany</groupId> <artifactId>mybatis-1</artifactId> <version>1.0.0</version> <properties> <!-- 项目构建使用的编码,避免中文乱码 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 源码编译 jdk 版本 --> <maven.compiler.source>1.8</maven.compiler.source> <!-- 运行代码的 jdk 版本 --> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <!-- 单元测试依赖 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!--mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml 文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <!-- filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 --> <filtering>false</filtering> </resource> </resources> </build> </project>
3、创建Java实体类User--保存表中的一行数据
package com.mycompany.domain; public class User { private int userId; private String userName; private String email; private int age; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
4、创建持久层的dao接口,定义操作数据库的方法
package com.mycompany.dao; import com.mycompany.domain.User; import java.util.List; public interface UserDao { /** * 查询user列表 * @param user 单个user用户 * @return user的list */ List<User> selectUserList(User user); /** * 插入user * @param user * @return */ int insertUser(User user); }
5、创建一个mybatis使用的配置文件 SQL映射文件
编写SQL语句,一般一个表对应一个SQL映射文件,这个文件就是xml文件
sql映射文件(sql mapper):编写SQL语句,mybatis负责执行这些SQL语句
1.指定约束文件
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- mybatis-3-mapper.dtd:约束文件名称
2.约束文件作用:限制,检查当前文件中出现的标签,属性必须符合mybatis的要求
3.<mapper>:当前文件根标签(必须的)
- namesace:命名空间(唯一值,自定义字符串;要求使用dao接口的全限定名称)
- 全限定类名:就是类名全称,带包路径的用点隔开,如: java.lang.String
- 即全限定名 = 包名 + 类型
- 非限定类名也叫短名,就是我们平时说的类名,不带包的,如:String
4.数据库增删改查特定标签
- <select>:查询,select语句
- <update>:更新,update语句
- <insert>:插入,insert语句
- <delete>:删除,delete语句
<?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"> <!-- sql映射文件(sql mapper):编写SQL语句,mybatis负责执行这些SQL语句 1、指定约束文件 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> mybatis-3-mapper.dtd:约束文件名称 2、约束文件作用:限制,检查当前文件中出现的标签,属性必须符合mybatis的要求 3、<mapper>:当前文件根标签(必须的) namespace:命名空间(唯一值,自定义字符串;要求使用dao接口的全限定名称) 全限定类名:就是类名全称,带包路径的用点隔开,如: java.lang.String 即全限定名 = 包名 + 类型 非限定类名也叫短名,就是我们平时说的类名,不带包的,如:String 4、数据库增删改查特定标签 <select>:查询,select语句 <update>:更新,update语句 <insert>:插入,insert语句 <delete>:删除,delete语句 --> <mapper namespace="com.mycompany.dao.UserDao"> <!-- <select>标签:查询操作 id:执行SQL语法的唯一标识,mybatis会根据这个id的值来找到要执行的SQL语句 可以自定义,一般要求使用接口中的方法名称 resultType:表示结果类型,SQL语句执行后得到ResultSet结果集,遍历这个结果集得到的Java对象类型 值写Java对象的全限定名称 --> <select id="selectUserList" resultType="com.mycompany.domain.User"> select user_Id,user_Name,email,age from user order by user_Id asc </select> <!--插入操作,字段名和Java实体类中字段保持一致--> <insert id="insertUser"> insert into user values(#{userId},#{userName},#{email},#{age}) </insert> </mapper>
6、创建mybatis的主配置文件 一个项目一个主配置文件
主配置文件提供了数据库的连接信息和SQL映射文件的位置信息
<?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"> <!-- mybatis的主配置文件:主要定义了数据库的配置信息,SQL映射文件的位置 1、约束文件 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> mybatis-3-config.dtd:约束文件名称 2、configuration:根标签 --> <configuration> <!-- settings:mybatis全局行为 --> <settings> <!-- 设置mybatis输出日志 --> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings> <!-- 环境配置:数据库的连接信息 default:必须和某个environment的id值一样 告诉mybatis使用哪个数据库的连接信息(访问哪个数据库) --> <environments default="development"> <!-- environment:一个数据库的配置,环境 id:一个唯一值(可自定义,表示环境的名称) --> <environment id="development"> <!-- transactionManaer:mybatis的事务类型 type:JDBC(表示使用JDBC中的Connection对象的commit,rollback做事务处理) --> <transactionManager type="JDBC"/> <!-- dataSource:表示数据源,连接数据库的 type:表述数据源的类型,POOLED表示使用连接池 --> <dataSource type="POOLED"> <!-- driver, user, username, password 是固定的,不能自定义。 --> <!-- 数据库驱动类名 --> <property name="driver" value="com.mysql.jdbc.Driver"/> <!-- 连接数据库的URL字符串 --> <property name="url" value="jdbc:mysql://localhost:3306/ssm"/> <!-- 访问数据库的用户名 --> <property name="username" value="root"/> <!-- 访问数据库的密码 --> <property name="password" value="123456"/> </dataSource> </environment> <!--表示线上的数据库,是项目真实使用的库--> <environment id="online"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/onlinedb"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!-- sql mapper(SQL映射文件)的位置 --> <mappers> <!-- 一个mapper标签指定一个文件的位置 从类路径开始的路径信息(target/classes)类路径 --> <mapper resource="com/mycompany/dao/UserDao.xml"/> </mappers> </configuration>
7、创建使用mybatis测试类(通过mybatis访问数据库)
public class TestMyBatis { /** * 查询user列表 */ @Test public void testSelectUserList(){ try { //访问mybatis读取user数据 //1、定义mybatis主配置文件名称,从类路径的根开始(target/clasess) String config = "mybatis-config.xml"; //2、读取config表示的文件 InputStream in = Resources.getResourceAsStream(config); //3、创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //4、创建SqlSessionFactory对象 SqlSessionFactory factory = builder.build(in); //5、获取SqlSession对象,从SqlSessionFactory中获取SqlSession(非自动提交事务,如果增删改需要手动提交事务) SqlSession sqlSession = factory.openSession(); //6、指定要执行的SQL语句标识;sql映射文件中的 namespace + "." + 标签的id值 String sqlId = "com.mycompany.dao.UserDao.selectUserList"; //7、执行sql语句,通过sqlId找到语句 List<User> userList = sqlSession.selectList(sqlId); //8、输出结果 for (User user:userList){ System.out.println("查询用户="+user); } //9、关闭SQLSession对象 sqlSession.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 查询user列表 */ @Test public void testMyBatisUtil(){ try { SqlSession sqlSession = MyBatisUtil.getSqlSession(); String sqlId = "com.mycompany.dao.UserDao.selectUserList"; //7、执行sql语句,通过sqlId找到语句 List<User> userList = sqlSession.selectList(sqlId); //8、输出结果 for (User user:userList){ System.out.println("查询用户="+user); } //9、关闭SQLSession对象 sqlSession.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 插入 */ @Test public void testInsertUser(){ SqlSession sqlSession = null; try { sqlSession = MyBatisUtil.getSqlSession(); String sqlId = "com.mycompany.dao.UserDao.insertUser"; //7、执行sql语句,通过sqlId找到语句 User user = new User(); user.setUserId(5); user.setUserName("zhangfei"); user.setEmail("zangfei@163.com"); user.setAge(16); int nums = sqlSession.insert(sqlId,user); //mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务 sqlSession.commit(); System.out.println("更新用户条数="+nums); //9、关闭SQLSession对象 sqlSession.close(); } catch (IOException e) { e.printStackTrace(); } } }
我们将SqlSession提取为工具类MyBatisUtil
public class MyBatisUtil { public MyBatisUtil() { } public static SqlSession getSqlSession() throws IOException { String config = "mybatis-config.xml"; InputStream ins = Resources.getResourceAsStream(config); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(ins); SqlSession sqlSession = factory.openSession(); return sqlSession; } }
(1)Resources
mybatis中的一个类, 负责读取主配置文件
//1、定义mybatis主配置文件名称,从类路径的根开始(target/clasess) String config = "mybatis-config.xml"; //2、读取config表示的文件 InputStream in = Resources.getResourceAsStream(config);
(2)SqlSessionFactoryBuilder :
创建SqlSessionFactory对象
//3、创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //4、创建SqlSessionFactory对象 SqlSessionFactory factory = builder.build(in);
(3)SqlSessionFactory
重量级对象, 程序创建一个对象耗时比较长,使用资源比较多;在整个项目中,有一个就够用
SqlSessionFactory
:接口 ,接口实现类: DefaultSqlSessionFactorySqlSessionFactory
作用:获取SqlSession对象
SqlSession sqlSession = factory.openSession();
openSession()方法
【1】openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
【2】openSession(boolean):
openSession(true)
获取自动提交事务的SqlSessionopenSession(false)
非自动提交事务的SqlSession对象
(4)SqlSession
SqlSession接口 :定义了操作数据的方法
例如 selectOne() ,selectList() ,insert(),update(),delete(),commit(),rollback()
SqlSession接口的实现类DefaultSqlSession。
使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
在执行完sql语句后,需要关闭它,执行SqlSession.close();这样能保证他的使用是线程安全的
9、整个mybatis框架的maven模块目录如下
10、常见报错问题
(1)找不到mybatis-config.xml文件或者对应的dao以及SQL映射文件
有如下三种解决方案
【1】clean一下,然后compile一下,会重新生成target目录
【2】Rebuild Project,再重新运行,就会在target目录下出现mybatis-config.xml文件
【3】以上两种方式不行,直接手动将src/resources/mybatis-config.xml文件拷贝至target/classes目录下
(2)dao接口的 方法 和 dao.xml映射文件中的 id 要保持一致
(3)数据库表中的列名,要和Java实体类中的字段,dao.xml映射文件的属性字段保持一致
11、 junit : 单元测试
- junit:单元测试, 一个工具类库,做测试方法使用的。
- 单元:指定的是方法, 一个类中有很多方法,一个方法称为单元
使用单元测试
(1)需要加入junit依赖
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>
(2)创建测试类
src/test/java目录中创建类
(3)创建测试方法
【1】public 方法
【2】没有返回值 void
【3】方法名称自定义,建议名称是test + 测试方法名称
【4】方法没有参数
【5】方法的上面加入 @Test ,方法可以单独执行;不用使用main方法
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。