myBatis框架之入门(一)

什么是框架

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

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

框架解决什么问题

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

什么时候使用框架

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

怎么使用框架

Java的框架是具有一些共性

  • 导入jar包

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

  • 调用框架中的api

原生JDBC案例

  • 查询user表

  • 以List集合形式返回

  • 编写pojo类 (User)

  • domain,pojo本质都是相同的

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;
    }


数据库的结构为:

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时候的结构思路图:

这是代码的结构图

 

 开始上代码:

 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();
    }
}

最后的结果为:

 

posted @ 2019-03-28 23:28  King-DA  阅读(146)  评论(0编辑  收藏  举报