myBatis框架之入门(一)

时间:2024-10-24 17:04:26

什么是框架

  框架就是一个架子,表演节目,舞台已经搭建好,表演什么节目,看自己的需求了。

  框架是一个半成品,对于Java语言来说,框架就是封装了别人的代码。在框架的基础上我们在进一步开发,拿来主义。

框架解决什么问题

解决的是技术整合问题。软件开发环境和规模都很大,不可能任何一个项目的代码都从零开始,此时就需要一个非常优秀的框架把基础技术整合完毕,我们在他的基础上进一步开发。提高性能,易扩展,易维护,最终提高整个团队的开发效率。

什么时候使用框架

企业级大型项目开发,避免大炮打蚊子。

怎么使用框架

Java的框架是具有一些共性

  • 导入jar包

  • 框架运行细节定义,也就是编写配置文件(xml)

  • 调用框架中的api

原生JDBC案例

  • 查询user表

  • 以List集合形式返回

  • 编写pojo类 (User)

  • domain,pojo本质都是相同的

myBatis框架之入门(一)

domain中的User类

package com.qingmu.domain;

/**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 19:53 2019/3/21
*/
public class User {
private int id; private String username; private String sex; private String birthday; private String address;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", birthday='" + birthday + '\'' +
", address='" + address + '\'' +
'}';
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public String getBirthday() {
return birthday;
} public void setBirthday(String birthday) {
this.birthday = birthday;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} 数据库的结构为:
myBatis框架之入门(一)

Dao层的接口

package com.qingmu.Dao;

import com.qingmu.domain.User;

import java.sql.SQLException;
import java.util.List; /**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 19:55 2019/3/21
*/
public interface UserDao {
List<User> userList() throws ClassNotFoundException, SQLException;
}

Dao层的实现类

package com.qingmu.Dao.Iml;

import com.qingmu.Dao.UserDao;
import com.qingmu.domain.User; import java.sql.*;
import java.util.ArrayList;
import java.util.List; /**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 19:56 2019/3/21
*/ /**
* 原生的jdbc的开发步骤为:
* 1.获取驱动
* 2.获取连接
* 3.获取操作sql语句的对象
* 4.获取结果集
* 5.处理结果集
* 6.释放资源
*/
public class UserDaoImpl implements UserDao { // 将driverClass,url,username,password作为这个类的成员变量
private String driverClass = "com.mysql.jdbc.Driver";
private String url = "jdbc:mysql://localhost:3306/mybatis?CharacterEncoding=utf-8";
private String username = "root";
private String password = "root"; /**
* 查询数据中的所有数据
*
* @return
* @throws ClassNotFoundException
* @throws SQLException
*/
@Override
public List<User> userList() throws ClassNotFoundException, SQLException {
// 创建一个集合,将所有的结果集存储在list集合中,
List<User> list = new ArrayList<User>();
// 注册驱动,使用反射进行加载
Class.forName(driverClass);
// 获取连接
Connection connection = DriverManager.getConnection(url, username, password);
// 获取执行sql语句的对象
String sql = "select * from user";
PreparedStatement psmt = connection.prepareStatement(sql);
// 获取结果集
ResultSet rs = psmt.executeQuery();
User user = null;
// 处理结果集
while (rs.next()) {
user = new User();
// 将结果集中的数据通过getObject()的方法取出来,存到javaBean中
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setBirthday(rs.getString("birthday"));
user.setSex(rs.getString("sex"));
user.setAddress(rs.getString("address"));
list.add(user);
}
// 释放资源.
rs.close();
psmt.close();
connection.close();
// 返回集合
return list;
}
}

Test类:

package com.qingmu;

import com.qingmu.Dao.Iml.UserDaoImpl;
import com.qingmu.Dao.UserDao;
import com.qingmu.domain.User;
import org.junit.Test; import java.sql.SQLException;
import java.util.List; /**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 20:06 2019/3/21
*/
public class MainTest { @Test
public void testJdbc() throws SQLException, ClassNotFoundException {
UserDao userDao = new UserDaoImpl();
List<User> users = userDao.userList();
for (User user : users) {
System.out.println(user);
}
}
}

原生JDBC案例的问题

  频繁连接,释放数据库资源,

  降低系统性能SQL语句硬编码,

  难以维护参数和占位符对应问题

  结果集解析复杂,列名硬编码

MyBatis框架

Mybatis原本是Apache软件基金会的一个开源项目叫做iBatis,2010年这个项目由
Apache迁移到了goole code管理才改名为Mybatis,2013年又迁移到了GitHub。
Mybatis是一个优秀的持久层框架(Dao层框架),它是对JDBC的封装,使得开发者只需
要关注Sql语句(业务)本身即可,无需开发者处理加载驱动、获取连接、创建
Statement等繁琐的过程。

Mybatis最大的特点是把Sql语句写在XML配置文件当中。而且Mybatis执行完Sql语句之
后可以以对象形式返回(POJO/POJO集合等)。

Mybatis是一个实现了ORM思想的持久层框架。
ORM:Object/Relation Mapping 对象/关系映射。

ORM思想:将数据库中的关系数据表映射为JAVA中的对象,把对数据表的操作转换为对
对象的操作,实现面向对象编程。因此ORM的目的是使得开发人员以面向对象的思想来
操作数据库。
比如:原来insert使用的是insert into…,如果使用实现了ORM思想的持久层框架,就可
以在Java程序中直接调用api,比如insert(User),达到操作对象即操作数据库的效果。
Hibernate框架是一个全自动的ORM持久层框架,只需要编写POJO,在xml中定义好
Pojo属性和数据表字段的映射/对应关系,就可以在java中实现类似 insert(User)的操
作。Sql语句都不用写。但是因为性能等问题,市场占有率越来越低
Mybatis框架是一个半自动的ORM持久层框架,也可以在Java中实现类似 insert(User)的
操作最终操作数据库,但是需要我们自己写Sql语句。Mybatis是目前比较流行的Dao层框
架。

自定义MyBatis框架:

  完整性和严谨性不能和真实的相比,只是自己按照MyBatis框架的思想,将这个过程进行的一个简单的拼接.

myBatis框架之入门(一)

上图为实现MyBatis时候的结构思路图:

这是代码的结构图

myBatis框架之入门(一)

开始上代码:

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.qingmu</groupId>
<artifactId>mybatis_qingmu_328</artifactId>
<version>1.0-SNAPSHOT</version> <name>mybatis_qingmu_328</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties> <dependencies>
<!--使用xpath引入-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<!--使用dom4j解析-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies> <build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

pojo包下的三个类:

配置文件类

Configuration 
package com.qingmu.pojo;

import java.util.HashMap;
import java.util.Map; /**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 16:21 2019/3/28
*/
public class Configuration {
private String driver;
private String url;
private String username;
private String password; /**
*   * Map集合键,通过namespace+"."+id 锁定唯一SQL语句
*   * Map集合值,Mapper对象,封装结果集pojo和SQL语句
*   
*/
private Map<String, Mapper> map = new HashMap<String, Mapper>(); public String getDriver() {
return driver;
} public void setDriver(String driver) {
this.driver = driver;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Configuration{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
", map=" + map +
'}';
} public Map<String, Mapper> getMap() {
return map;
} public void setMap(Map<String, Mapper> map) {
this.map = map;
}
}

User类

package com.qingmu.pojo;

import java.util.Date;

/**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 21:10 2019/3/28
*/
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public Date getBirthday() {
return birthday;
} public void setBirthday(Date birthday) {
this.birthday = birthday;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", birthday='" + birthday + '\'' +
", address='" + address + '\'' +
'}';
}
}

Mapper类:

package com.qingmu.pojo;

/**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 16:47 2019/3/28
*/
public class Mapper {
private String sql;
private String resultType; @Override
public String toString() {
return "Mapper{" +
"sql='" + sql + '\'' +
", resultType='" + resultType + '\'' +
'}';
} public String getSql() {
return sql;
} public void setSql(String sql) {
this.sql = sql;
} public String getResultType() {
return resultType;
} public void setResultType(String resultType) {
this.resultType = resultType;
}
}

resource包中的两个配置文件

SqlMapConfig文件

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments> <mappers>
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>

UserMapper文件

<?xml version="1.0" encoding="utf-8" ?>

<mapper namespace="test">
<select id="queryUserList" resultType="com.qingmu.pojo.User">
select * from user
</select>
</mapper>

fram包下的三个类

sqlsessionFactoryBuilder类

package com.qingmu.fram;

/**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 16:20 2019/3/28
*/ import com.qingmu.pojo.Configuration;
import com.qingmu.pojo.Mapper;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; import java.io.InputStream;
import java.util.List; /**
* sqlSessionFactory工厂构建者
* 读取xml文件
*/
public class SqlSesisonFactoryBuilder {
/**
* 返回sqlsessionFactory工厂
* 接收一个字节输入流
* 用户携带流
*/
public SqlSessionFactory builder(InputStream inputStream) {
// 创建一个工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactory();
// 获取配置文件对象,读取sqlMapperConfig.xml文件
Configuration configuration = loadXmlconfig(inputStream);
// 将配置文件对象,传入到sqlSessionFactory中
sqlSessionFactory.setConfiguration(configuration);
return sqlSessionFactory;
} /**
* 解析xml文件用来装配配置对象
*
* @param inputStream
* @return
*/
private Configuration loadXmlconfig(InputStream inputStream) {
// 获取配置文件对象
Configuration configuration = new Configuration();
// 使用dom4j读取文件
SAXReader saxReader = new SAXReader();
try {
// 读取xml文件,获取到document对象
Document document = saxReader.read(inputStream);
// 获取根标签
Element rootElement = document.getRootElement();
// 使用xpath表达式读取文件(可以读取节点)
List<Element> list = rootElement.selectNodes("//property");
if (list != null && list.size() > 0) {
for (Element element : list) {
// 属性值
String name = element.attributeValue("name");
String value = element.attributeValue("value");
if ("driver".equals(name)) {
configuration.setDriver(value);
} else if ("url".equals(name)) {
configuration.setUrl(value);
} else if ("password".equals(name)) {
configuration.setUsername(value);
} else if ("username".equals(name)) {
configuration.setPassword(value);
}
}
}
// 解析mapper标签
List<Element> list1 = rootElement.selectNodes("//mapper");
if (list1 != null && list1.size() > 0) {
for (Element element : list1) {
// 获取出来xml文件名字,用来绑定流对象,用来读取文件
String resource = element.attributeValue("resource");
// 解析UserMapper文件的方法
loadSqlConfig(resource, configuration);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return configuration;
} /**
* 解析UserMapper文件的方法
* @param resource
* @param configuration
*/
private void loadSqlConfig(String resource, Configuration configuration) {
// 用来绑定流对象,用来读取文件
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource);
SAXReader saxReader = new SAXReader();
try {
// 获取出来doucument对象
Document document = saxReader.read(inputStream);
// 获取根标签
Element rootElement = document.getRootElement();
// 使用根标签获取出来namespace属性
String namespace = rootElement.attributeValue("namespace");
// 获取节点
List<Element> list = rootElement.selectNodes("//select");
if (list != null && list.size() > 0) {
for (Element element : list) {
// 获取标签内的文本(sql)
String sql = element.getText();
// 获取结果类型
String resultType = element.attributeValue("resultType");
// 获取出来id
String id = element.attributeValue("id");
Mapper mapper = new Mapper();
mapper.setSql(sql);
mapper.setResultType(resultType);
configuration.getMap().put(namespace + "." + id, mapper);
}
} } catch (Exception ex) {
ex.printStackTrace();
}
} }

sqlSessionFacyory类

package com.qingmu.fram;

import com.qingmu.pojo.Configuration;

/**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 16:19 2019/3/28
*/
public class SqlSessionFactory { private Configuration configuration; public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
} /**
* 获取出来sqlSession对象
*/
public SqlSession openSession(){
return new SqlSessionImpl(configuration);
} }

sqlSession接口

package com.qingmu.fram;

import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List; /**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 16:58 2019/3/28
*/
public interface SqlSession {
public <T> List<T> selectList(String sqlId) throws ClassNotFoundException, SQLException, IllegalAccessException, InstantiationException, InvocationTargetException;
}

sqlSession实现类

package com.qingmu.fram;

import com.qingmu.pojo.Configuration;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List; /**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 16:57 2019/3/28
*/
public class SqlSessionImpl implements SqlSession {
// xml文件配置对象
private Configuration configuration;
private String driverClass ;
private String url ;
private String username ;
private String password ;
//使用构造方法进行初始化
public SqlSessionImpl(Configuration configuration) {
this.configuration = configuration;
driverClass = configuration.getDriver();
url = configuration.getUrl();
username = configuration.getUsername();
password = configuration.getPassword();
} @Override
public <T> List<T> selectList(String sqlId) throws ClassNotFoundException, SQLException, IllegalAccessException, InstantiationException, InvocationTargetException {
// 创建一个空的集合,用来存储需要存放的元素
List<T> arrayList = new ArrayList<T>();
// 使用反射获取驱动
Class.forName(driverClass);
// 获取连接
Connection connection = DriverManager.getConnection(url, username, password);
// 获取到sql语句
String sql = configuration.getMap().get(sqlId).getSql();
// 创建操作sql语句的对象
PreparedStatement psmt = connection.prepareStatement(sql);
// 获取结果集
ResultSet resultSet = psmt.executeQuery();
// 获取出来元数据
ResultSetMetaData metaData = resultSet.getMetaData();
// 创建一个集合用来存储列名
ArrayList<String> cloumnNamelist = new ArrayList<>();
// 如果小于的话,会少最好一列(获取到列的总数为metaData.getColumnCount())
for(int i=1;i<=metaData.getColumnCount();i++){
// 获取出来列名,并存储到集合中
cloumnNamelist.add(metaData.getColumnName(i));
}
Object obj = null;
// 配置文件,获取结果集封装的pojo对象的全限定名
String resultType = configuration.getMap().get(sqlId).getResultType();
// 使用反射获取出来User类
Class<?> clazz = Class.forName(resultType);
// 通过反射获取到方法(表示类或者接口声明的所有方法.)
Method[] methods = clazz.getDeclaredMethods();
// 处理结果集
while(resultSet.next()){
// 反射创建对象
obj = clazz.newInstance();
// 遍历集合,获取列名
for (String cloumnName : cloumnNamelist) {
// 通过列名,获取到列中所对应的值
Object columvalue = resultSet.getObject(cloumnName);
System.out.println(columvalue);
// 遍历方法数组
for (Method method : methods) {
// 获取到方法名
String methodName = method.getName();
// 判断列名是否和set+方法名相同
if(methodName.equalsIgnoreCase("set"+cloumnName)){
// 调用方法,并进行传参
method.invoke(obj,columvalue);
}
}
}
// 对象存储到集合
arrayList.add((T)obj);
}
return arrayList;
}
}

Test类

package com.qingmu;

import com.qingmu.fram.SqlSesisonFactoryBuilder;
import com.qingmu.fram.SqlSession;
import com.qingmu.fram.SqlSessionFactory;
import com.qingmu.pojo.User;
import org.junit.Test; import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List; /**
* @Auther:qingmu
* @Description:脚踏实地,只为出人头地
* @Date:Created in 21:13 2019/3/28
*/
public class ATest {
@Test
public void mybatisTest() throws ClassNotFoundException, SQLException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
// 创建工厂创建者对象
SqlSesisonFactoryBuilder sqlSesisonFactoryBuilder = new SqlSesisonFactoryBuilder();
// 使用本类,类加载器获取流,并且绑定 读取sqlMapConfig.xml文件
InputStream inputStream = ATest.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
// 使用工厂创建者对象,传入流,创建工厂对象
SqlSessionFactory sqlSessionFactory = sqlSesisonFactoryBuilder.builder(inputStream);
// 调用对象,创建sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 使用selectList方法,传入唯一标识,获取到一个集合.
List<User> userList = sqlSession.selectList("test.queryUserList");
if(userList != null && userList.size() > 0){
for(User user : userList){
System.out.println(user);
}
}
inputStream.close();
}
}

最后的结果为:

myBatis框架之入门(一)