自定义一个简单ORM框架(类似Hibernate)

       上一篇通过跟踪源码的方式剖析了Hibernate和MyBatis两个框架是如何应用ORM思想的,接下来自己定义一个简单的ORM框架(名为MiniORM),希望能通过这种方式零距离的去应用一下ORM。

1、MiniORM框架的结构设计

第一层为配置层:

  1. miniORM.cfg.xml是框架的核心配置文件,主要用来设置数据库连接信息和映射配置文件路径信息
  2. Xxx.mapper.xml是框架的映射配置文件,主要用来设置类和表之间以及属性和字段之间的映射关系
  3. Xxx.java是带有映射注解的实体类,主要用来设置类和表之间以及属性和字段之间的映射关系,和Xxx.mapper.xml的作用一样,只不过采用的是注解方式,两者二选一

第二层为解析层:

  1. Dom4jUtil类用来解析miniORM.cfg.xml和Xxx.mapper.xml两个配置文件的数据
  2. AnnotationUtil类用来解析实体类中的映射注解

第三层为封装层:

  1. ORMConfig类用来封装和存储从miniORM.cfg.xml文件中解析得到的数据
  2. Mapper类用来封装和存储从Xxx.mapper.xml或实体类中解析得到的映射数据

第四层为功能层:

  1. ORMSession类主要用来从ORMConfig和Mapper中获取相关数据,然后生成sql语句,最后通过对JDBC的封装最终实现增删改查功能

2、MiniORM框架的代码实现

2.1 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.zdw.orm</groupId>
    <artifactId>MiniORM</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>MiniORM</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                        <!--<compilerArguments>
                            <bootclasspath>${JAVA_HOME}/jre/lib/rt.jar</bootclasspath>
                        </compilerArguments>-->
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

MiniORM框架依赖dom4j和jdk1.8, 编译时会打成jar包并install到本地仓库中。

2.2 miniORM.cfg.xml

miniORM.cfg.xml是框架的核心配置文件,主要用来设置数据库连接信息和映射配置文件路径信息,源码如下所示:

<?xml version='1.0' encoding='utf-8'?>
<orm-factory>
<!--数据库连接数据-->
    <property name="connection.url">jdbc:mysql://localhost:3306/test</property>
    <property name="connection.driverClass">com.mysql.jdbc.Driver</property>
    <property name="connection.username">root</property>
    <property name="connection.password">123</property>

    <!--采用xml配置映射数据-->
    <mapping resource="cn/zdw/orm/entity/Book.mapper.xml"/>
    <!--采用实体类注解配置映射数据-->
    <entity package="cn.zdw.orm.entity"/>
</orm-factory>

2.3 Xxx.mapper.xml映射文件

Xxx.mapper.xml是框架的映射配置文件,主要用来设置类和表之间以及属性和字段之间的映射关系,以Book.mapper.xml为例,源码如下所示:

<?xml version='1.0' encoding='UTF-8'?>
<!--实体类和表之间的映射关系配置-->
<orm-mapping>
    <class name="cn.itcast.orm.entity.Book" table="t_book">
        <id name="id" column="bid"/>
        <property name="name" column="bname"/>
        <property name="author" column="author"/>
        <property name="price" column="price"/>
    </class>
</orm-mapping>

2.4 定义自定义注解

2.4.1 @ORMTable

package com.zdw.orm.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//该注解用来设置表名
@Retention(RetentionPolicy.RUNTIME) //运行期间保留注解的信息
@Target(ElementType.TYPE) //设置注解用到什么地方
public @interface ORMTable {
    public String name() default "";
}

2.4.2 @ORMId

package com.zdw.orm.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//该注解用来设置注解
@Retention(RetentionPolicy.RUNTIME) //运行期间保留注解的信息
@Target(ElementType.FIELD) //设置注解用到什么地方
public @interface ORMId {
}

2.4.3 @ORMColumn

package com.zdw.orm.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//该注解用来设置字段名
@Retention(RetentionPolicy.RUNTIME) //运行期间保留注解的信息
@Target(ElementType.FIELD) //设置注解用到什么地方
public @interface ORMColumn {
    public String name() default "";
}

2.5 注解方式

当然MiniORM框架也支持在实体类上以注解方式去配置映射关系,以Book.java为例,源码如下所示:

//实体类:图书
@ORMTable(name = "t_book")
public class Book {

    @ORMId
    @ORMColumn(name = "bid")
    private int id;  //主键

    @ORMColumn(name="bname")
    private String name; //图书名字

    @ORMColumn(name="author")
    private String author;  //图书作者

    @ORMColumn(name="price")
    private double price;  //图书价格
    //... ...
}

       实体类中的@ORMTable、@ORMId、@ORMColumn是我们自定义的三个注解,@ORMTable用来设置当前类和哪个表对应,@ORMColumn用来设置当前属性和表中哪个字段对应,@ORMId用来设置哪个属性对应的字段是主键。

2.6 Dom4jUtil类

Dom4jUtil类是一个基于Dom4j的工具类,主要用来解析miniORM.cfg.xml和Xxx.mapper.xml,源码如下所示:

package com.zdw.orm.utils;

import java.io.File;
import java.util.*;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 基于dom4j的工具类
 */
public class Dom4jUtil {

    /**
     * 通过文件的路径获取xml的document对象
     *
     * @param path 文件的路径
     * @return 返回文档对象
     */
    public static Document getXMLByFilePath(String path) {
        if (null == path) {
            return null;
        }
        Document document = null;
        try {
            SAXReader reader = new SAXReader();
            document = reader.read(new File(path));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return document;
    }

    /**
     * 获得某文档中某元素内某属性的值和元素的文本信息
     *
     * @param document    xml文档对象
     * @param elementName 元素名
     * @param attrName    属性名
     * @return 返回一个Map集合
     */
    public static Map<String, String> Elements2Map(Document document, String elementName, String attrName) {
        List<Element> propList = document.getRootElement().elements(elementName);
        Map<String, String> propConfig = new HashMap<>();
        for (Element element : propList) {
            String key = element.attribute(attrName).getValue();
            String value = element.getTextTrim();
            propConfig.put(key, value);
        }
        return propConfig;
    }

    /**
     * 针对mapper.xml文件,获得映射信息并存到Map集合中
     *
     * @param document xml文档对象
     * @return 返回一个Map集合
     */
    public static Map<String, String> Elements2Map(Document document) {
        Element classElement = document.getRootElement().element("class");
        Map<String, String> mapping = new HashMap<>();

        Element idElement = classElement.element("id");
        String idKey = idElement.attribute("name").getValue();
        String idValue = idElement.attribute("column").getValue();
        mapping.put(idKey, idValue);

        List<Element> propElements = classElement.elements("property");
        for (Element element : propElements) {
            String propKey = element.attribute("name").getValue();
            String propValue = element.attribute("column").getValue();
            mapping.put(propKey, propValue);
        }
        return mapping;
    }

    /**
     * 针对mapper.xml文件,获得主键的映射信息并存到Map集合中
     *
     * @param document xml文档对象
     * @return 返回一个Map集合
     */
    public static Map<String, String> ElementsID2Map(Document document) {
        Element classElement = document.getRootElement().element("class");
        Map<String, String> mapping = new HashMap<>();

        Element idElement = classElement.element("id");
        String idKey = idElement.attribute("name").getValue();
        String idValue = idElement.attribute("column").getValue();
        mapping.put(idKey, idValue);

        return mapping;
    }

    /**
     * 获得某文档中某元素内某属性的值
     *
     * @param document    xml文档对象
     * @param elementName 元素名
     * @param attrName    属性名
     * @return 返回一个Set集合
     */
    public static Set<String> Elements2Set(Document document, String elementName, String attrName) {
        List<Element> mappingList = document.getRootElement().elements(elementName);
        Set<String> mappingSet = new HashSet<>();
        for (Element element : mappingList) {
            String value = element.attribute(attrName).getValue();
            mappingSet.add(value);
        }
        return mappingSet;
    }

    /**
     * 获得某文档中某元素内某属性的值
     *
     * @param document    xml文档对象
     * @param elementName 元素名
     * @param attrName    属性名
     * @return 返回一个Set集合
     */
    public static String getPropValue(Document document, String elementName, String attrName) {
        Element element = (Element) document.getRootElement().elements(elementName).get(0);
        return element.attribute(attrName).getValue();
    }
}

2.7 AnnotationUtil

AnnotationUtil类主要用来通过反射技术解析实体类中的注解,从而获得映射数据。

package com.zdw.orm.utils;

import com.zdw.orm.annotation.ORMColumn;
import com.zdw.orm.annotation.ORMId;
import com.zdw.orm.annotation.ORMTable;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/*
    使用反射解析实体类中注解的工具类
 */
public class AnnotationUtil {

    /*
    得到的类名
     */
    public static String getClassName(Class clz) {
        return clz.getName();
    }

    /*
    得到ORMTable注解中的表名
     */
    public static String getTableName(Class clz) {
        if (clz.isAnnotationPresent(ORMTable.class)) {
            ORMTable ormTable = (ORMTable) clz.getAnnotation(ORMTable.class);
            return ormTable.name();
        } else {
            System.out.println("缺少ORMTable注解");
            return null;
        }
    }

    /*
    得到主键属性和对应的字段
     */
    public static Map<String, String> getIdMapper(Class clz) {
        boolean flag = true;
        Map<String, String> map = new HashMap<>();
        Field[] fields = clz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(ORMId.class)) {
                flag = false;
                String fieldName = field.getName();
                if (field.isAnnotationPresent(ORMColumn.class)) {
                    ORMColumn ormColumn = field.getAnnotation(ORMColumn.class);
                    String columnName = ormColumn.name();
                    map.put(fieldName, columnName);
                    break;
                } else {
                    System.out.println("缺少ORMColumn注解");
                }
            }
        }
        if (flag) {
            System.out.println("缺少ORMId注解");
        }
        return map;
    }

    /*
    得到类中所有属性和对应的字段
     */
    public static Map<String, String> getPropMapping(Class clz) {
        Map<String, String> map = new HashMap<>();
        map.putAll(getIdMapper(clz));
        Field[] fields = clz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(ORMColumn.class)) {
                ORMColumn ormColumn = field.getAnnotation(ORMColumn.class);
                String fieldName = field.getName();
                String columnName = ormColumn.name();
                map.put(fieldName, columnName);
            }
        }
        return map;
    }

    /*
    获得某包下面的所有类名
     */
    public static Set<String> getClassNameByPackage(String packagePath) {  //cn.itcast.orm.entity
        Set<String> names = new HashSet<>();
        String packageFile = packagePath.replace(".", "/");
        String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        if (classpath == null) {
            classpath = Thread.currentThread().getContextClassLoader().getResource("/").getPath();
        }
        try {
            classpath = java.net.URLDecoder.decode(classpath, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        File dir = new File(classpath + packageFile);
        if (dir.exists()) {
            File[] files = dir.listFiles();
            for (File f : files) {
                String name = f.getName();
                if (f.isFile() && name.endsWith(".class")) {
                    name = packagePath + "." + name.substring(0, name.lastIndexOf("."));
                    names.add(name);
                }
            }
        } else {
            System.out.println("包路径不存在");
        }
        return names;
    }
}

2.8 Mapper类

package com.zdw.orm.core;

import java.util.HashMap;
import java.util.Map;

/**
 * 该类用来封装和存储映射信息
 */
public class Mapper {
    private String className; //类名

    private String tableName; //表名

    private Map<String,String> idMapper = new HashMap<>(); //主键信息

    private Map<String,String> propMapper = new HashMap<>(); //普通的属性和字段信息
    //get/set方法和toString方法
}

2.9 ORMConfig类

package com.zdw.orm.core;

import com.zdw.orm.utils.AnnotationUtil;
import com.zdw.orm.utils.Dom4jUtil;
import org.dom4j.Document;

import java.io.File;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Create By zdw on 2019/7/16
 * 该类用来解析并封装框架的核心配置文件MiniORM.cfg.xml中的数据
 */
public class ORMConfig {
    private static String classpath; //classpath路径
    private static File cfgFile; // 核心配置文件
    private static Map<String,String> propConfig; // <property>标签中的数据
    private static Set<String> mappingSet; //映射配置文件路径
    private static Set<String> entitySet; //实体类
    public static List<Mapper> mapperList; // 映射信息

    static {
        //得到的classpath路径
        classpath=Thread.currentThread().getContextClassLoader().getResource("").getPath();
        //针对中文路径进行转码
        try {
            classpath = URLDecoder.decode(classpath, "utf-8");
        }catch (Exception e){
            e.printStackTrace();
        }
        //得到核心配置文件
        System.out.println(classpath);
        cfgFile=new File(classpath + "miniORM.cfg.xml");
        if(cfgFile.exists()){
            // 解析核心配置文件中的数据
            Document document= Dom4jUtil.getXMLByFilePath(cfgFile.getPath());
            propConfig=Dom4jUtil.Elements2Map(document,"property","name");
            mappingSet=Dom4jUtil.Elements2Set(document,"mapping","resource");
            entitySet=Dom4jUtil.Elements2Set(document,"entity","package");
        }else {
            cfgFile = null;
            System.out.println("未找到核心配置文件miniORM.cfg.xml");
        }
    }

    //从propConfig集合中获取数据并连接数据库
    private Connection getConnection() throws  Exception{
        String url=propConfig.get("connection.url");
        String driverClass=propConfig.get("connection.driverClass");
        String username=propConfig.get("connection.username");
        String password=propConfig.get("connection.password");

        Class.forName(driverClass);//加载数据库驱动
        Connection connection= DriverManager.getConnection(url,username,password);//获得数据库连接
        connection.setAutoCommit(true);//设置自动提交事务
        return  connection;
    }

    private void getMapping () throws  Exception{

        mapperList = new ArrayList<>();

        //1. 解析xxx.mapper.xml文件拿到映射数据
        for (String xmlPath:mappingSet){
            Document document=Dom4jUtil.getXMLByFilePath(classpath+xmlPath);
            String className=Dom4jUtil.getPropValue(document,"class","name");//获得某文档中某元素内某属性的值
            String tableName=Dom4jUtil.getPropValue(document,"class","table");
            Map<String,String> id_id=Dom4jUtil.ElementsID2Map(document);//获得主键的映射信息并存到Map集合中
            Map<String,String> mapping = Dom4jUtil.Elements2Map(document);//获得映射信息并存到Map集合中

            Mapper mapper=new Mapper();
            mapper.setTableName(tableName);
            mapper.setClassName(className);
            mapper.setIdMapper(id_id);
            mapper.setPropMapper(mapping);

            mapperList.add(mapper);
        }

        //2. 解析实体类中的注解拿到映射数据
        for(String packagePath:entitySet){
            Set<String> nameSet= AnnotationUtil.getClassNameByPackage(packagePath);
            for(String name:nameSet){
                Class clz=Class.forName(name);
                String className=AnnotationUtil.getClassName(clz);
                String tableName=AnnotationUtil.getTableName(clz);
                Map<String,String> id_id=AnnotationUtil.getIdMapper(clz);//得到主键属性和对应的字段
                Map<String,String> mapping=AnnotationUtil.getPropMapping(clz);//得到类中所有属性和对应的字段

                Mapper mapper=new Mapper();
                mapper.setTableName(tableName);
                mapper.setClassName(className);
                mapper.setIdMapper(id_id);
                mapper.setPropMapper(mapping);

                mapperList.add(mapper);
            }
        }
    }

    //创建ORMSession对象
    public ORMSession buildORMSession() throws  Exception{
        //1. 连接数据库
        Connection connection=this.getConnection();

        //2. 得到映射数据
        this.getMapping();

        //3. 创建ORMSession对象
        return  new ORMSession(connection);

    }
}

2.10 ORMSession 

package com.zdw.orm.core;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Create By zdw on 2019/7/17
 * 该类生成sql并实现增删改查功能
 */
public class ORMSession {
    private Connection connection;

    public ORMSession(Connection conn) {
        this.connection = conn;
    }

    //保存数据
    public void save(Object entity) throws Exception {
        String insertSQL = "";//最终的合成的sql语句

        //1. 从ORMConfig中获得保存有映射信息的集合
        List<Mapper> mapperList = ORMConfig.mapperList;

        //2. 遍历集合,从集合中找到和entity参数相对应的mapper对象
        for (Mapper mapper : mapperList) {
            if (mapper.getClassName().equals(entity.getClass().getName())) {
                String tableName = mapper.getTableName();
                String insertSQL1 = "insert into " + tableName + "( ";
                String insertSQL2 = " ) values ( ";

                //3. 得到当前对象所属类中的所有属性
                Field[] fields = entity.getClass().getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    //4. 遍历过程中根据属性得到字段名
                    String columnName = mapper.getPropMapper().get(field.getName());
                    //5. 遍历过程中根据属性得到它的值
                    String columnValue = field.get(entity).toString();
                    //6. 拼接sql语句
                    insertSQL1 += columnName + ",";
                    insertSQL2 += "'" + columnValue + "',";
                }
                //拼接的时候要去掉最后一次拼接的  , 号
                insertSQL = insertSQL1.substring(0, insertSQL1.length() - 1) + insertSQL2.substring(0, insertSQL2.length() - 1) + " )";
                break;
            }
        }

        // 把sql语句打印到控制台
        System.out.println("MiniORM-save: " + insertSQL);

        //7. 通过JDBC发送并执行sql
        PreparedStatement statement = connection.prepareStatement(insertSQL);
        statement.executeUpdate();
        statement.close();
    }

    //根据主键进行数据删除  delete from  表名  where 主键 = 值
    public void delete(Object entity) throws Exception {
        String delSQL = "delete from ";

        //1. 从ORMConfig中获得保存有映射信息的集合
        List<Mapper> mapperList = ORMConfig.mapperList;

        //2. 遍历集合,从集合中找到和entity参数相对应的mapper对象
        for (Mapper mapper : mapperList) {
            if (mapper.getClassName().equals(entity.getClass().getName())) {
                // 3. 得到我们想要的mapper对象,并得到表名
                String tableName = mapper.getTableName();
                delSQL += tableName + " where ";
                // 4. 得到主键的字段名和属性名
                Object[] idProp = mapper.getIdMapper().keySet().toArray(); //idProp[0]
                Object[] idColumn = mapper.getIdMapper().values().toArray(); //idColumn[0]

                // 5. 得到主键的值
                Field field = entity.getClass().getDeclaredField(idProp[0].toString());
                field.setAccessible(true);
                String idVal = field.get(entity).toString();

                // 6. 拼接sql
                delSQL += idColumn[0].toString() + " = " + idVal;
                // 把sql语句打印到控制台
                System.out.println("MiniORM-delete: " + delSQL);

                break;
            }

        }
        //7. 通过JDBC发送并执行sql
        PreparedStatement statement = connection.prepareStatement(delSQL);
        statement.executeUpdate();
        statement.close();
    }

    // 根据主键进行查询  select * from 表名 where  主键字段 = 值
    public Object findOne(Class clz, Object id) throws  Exception{

        String querySQL = "select * from ";

        //1. 从ORMConfig中得到存有映射信息的集合
        List<Mapper> mapperList=ORMConfig.mapperList;

        //2. 遍历集合拿到我们想要的mapper对象
        for (Mapper mapper : mapperList) {
            if (mapper.getClassName().equals(clz.getName())) {

                // 3. 获得表名
                String tableName = mapper.getTableName();

                //4. 获得主键字段名
                Object[] idColumn = mapper.getIdMapper().values().toArray(); //idColumn[0]

                //5. 拼接sql
                querySQL += tableName + " where " + idColumn[0].toString() + " = " + id;

                break;
            }
        }

        System.out.println("MiniORM-findOne:" +querySQL);

        //6. 通过jdbc发送并执行sql, 得到结果集
        PreparedStatement statement=connection.prepareStatement(querySQL);
        ResultSet rs=statement.executeQuery();

        //7. 封装结果集,返回对象
        if(rs.next()){
            // 查询到一行数据
            // 8.创建一个对象,目前属性的值都是初始值
            Object obj=clz.newInstance();
            // 9. 遍历mapperList集合找到我们想要的mapper对象
            for(Mapper mapper:mapperList){
                if (mapper.getClassName().equals(clz.getName())) {
                    //10. 得到存有属性-字段的映射信息
                    Map<String,String> propMap = mapper.getPropMapper();
                    //11. 遍历集合分别拿到属性名和字段名
                    Set<String> keySet = propMap.keySet();
                    for(String prop:keySet){  //prop就是属性名
                        String column = propMap.get(prop);   //column就是和属性对应的字段名
                        Field field = clz.getDeclaredField(prop);
                        field.setAccessible(true);
                        field.set(obj,rs.getObject(column));
                    }
                    break;
                }
            }
            //12. 释放资源
            statement.close();
            rs.close();

            //13. 返回查询出来的对象
            return obj;

        }else {
            // 没有查到数据
            return null;
        }

    }

    //关闭连接,释放资源
    public void close() throws  Exception{
        if(connection!=null){
            connection.close();
            connection = null;
        }
    }
}

编写完成之后,执行install命令,把该工程以jar包的形式安装到本地仓库,接下来的测试工程就可以引入这个依赖了。

 

3、测试MiniORM框架

创建一个测试工程MiniORMDemo,项目的工程结构如下:

3.1 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.zdw.orm</groupId>
    <artifactId>MiniORMDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.zdw.orm</groupId>
            <artifactId>MiniORM</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.36</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>  <!--为了编译时能加载包中的xml文件-->
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>  <!--为了编译时能加载resources中的xml文件-->
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
</project>

3.2 miniORM.cfg.xml

<?xml version="1.0" encoding="UTF-8" ?>
<orm-factory>
    <!--数据库连接-->
    <property name="connection.url">jdbc:mysql://localhost:3306/test</property>
    <property name="connection.driverClass">com.mysql.jdbc.Driver</property>
    <property name="connection.username">root</property>
    <property name="connection.password">123</property>

    <!--采用xml配置映射数据-->
    <mapping resource="com/zdw/orm/entity/Book.mapper.xml"/>

    <!--采用注解配置映射数据-->
    <entity package="com.zdw.orm.entity"/>
</orm-factory>

 

3.3 实体类Book

package com.zdw.orm.entity;

import com.zdw.orm.annotation.ORMColumn;
import com.zdw.orm.annotation.ORMId;
import com.zdw.orm.annotation.ORMTable;

/**
 * Create By zdw on 2019/7/17
 */
@ORMTable(name = "t_book")
public class Book {
    @ORMId
    @ORMColumn(name = "bid")
    private int id;  //主键

    @ORMColumn(name="bname")
    private String name; //图书名字

    @ORMColumn(name="author")
    private String author;  //图书作者

    @ORMColumn(name="price")
    private double price;  //图书价格

    //get/set方法和toString方法
}

3.4 实体类对应的映射文件

<?xml version='1.0' encoding='UTF-8'?>
<!--实体类和表之间的映射关系配置-->
<orm-mapping>
    <class name="com.zdw.orm.entity.Book" table="t_book">
        <id name="id" column="bid"/>
        <property name="name" column="bname"/>
        <property name="author" column="author"/>
        <property name="price" column="price"/>
    </class>
</orm-mapping>

其实对于映射文件和实体类种的注解,在实际开发种只需要使用一种即可。

3.5 测试类

这里需要注意的一点就是测试不要创建在test/java目录下,直接创建在main/java目录下就好,否则启动会报找不到miniORM.cfg.xml文件的错误

package com.zdw.orm.test;

import com.zdw.orm.core.ORMConfig;
import com.zdw.orm.core.ORMSession;
import com.zdw.orm.entity.Book;
import org.junit.Before;
import org.junit.Test;

/**
 * Create By zdw on 2019/7/17
 */
public class BookDao {

    private ORMConfig config;

    @Before
    public void init() {
        config = new ORMConfig();//创建核心配置类对象的时候,里面的静态代码块就会执行,就会解析miniORM.cfg.xml配置文件,得到相关信息
    }

    @Test
    public void testSave() throws Exception {
        ORMSession session = config.buildORMSession();
        Book book = new Book();
        book.setId(100);
        book.setName("你坏");
        book.setAuthor("大冰");
        book.setPrice(129.8);
        session.save(book);
        session.close();
    }

    @Test
    public void testDelete() throws Exception {
        ORMSession session = config.buildORMSession();
        Book book = new Book();
        book.setId(100);
        session.delete(book);
        session.close();
    }

    @Test
    public void testFindOne() throws Exception {
        ORMSession session = config.buildORMSession();
        Book book = (Book) session.findOne(Book.class, 100);
        System.out.println(book);
        session.close();
    }
}

 

以上内容参考自传智播客的教学资料。

源码下载地址:https://download.csdn.net/download/zengdongwen/11374084

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值