您的位置:首页 > 数据库 > SQL

自己实现一个简单的Mybatis框架

2018-03-11 12:44 483 查看
接上一篇自己写一个简单的Struts框架(3)

开发环境: win10,jdk1.8,tomcat9,mysql,MyEclipse

写一个简单的与数据库进行交互的框架,集成简单的打开关闭数据库,增删改查的功能。还有OR-Mapping的功能,使框架能够实现把对对象的CRUD操作映射到数据库表中,并用代理的方式实现懒加载的功能。

SimpleController工程目录:



抽象类BaseDao

抽象类BaseDao实现了打开关闭数据库的方法,并定义了增删改查四个基本操作的定义,用于规范实现他的类。

package sc.ustc.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public abstract class BaseDao {

protected String driver;
protected String url;
protected String userName;
protected String password;

public Connection openDBConnection() throws ClassNotFoundException, SQLException {

Class.forName(driver);

if (userName != null && !userName.isEmpty()) {

return DriverManager.getConnection(url, userName, password);
} else {

return DriverManager.getConnection(url);
}
}

public boolean closeDBConnection(Connection connection) throws SQLException {

if (connection != null) {
connection.close();
return true;
}
return false;
}

public abstract boolean insert(String sql);

public abstract boolean delete(String sql);

public abstract boolean update(String sql);

public abstract Object query(String sql, String[] args);

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


Configuration 解析or-mapping.xml配置文件

Configuration类实现了解析or-mapping.xml配置文件的方法,包括解析得到jdbc配置以及javabean映射数据库表的映射关系。

package sc.ustc.dao;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import sc.ustc.bean.OR_class;

public class Configuration {

private static String path = Thre
4000
ad.currentThread().getContextClassLoader().getResource("or_mapping.xml").getPath();

public static Map<String, String> jdbc_config() {
try {
Document document = getDoc();
NodeList jdbc = document.getElementsByTagName("jdbc");
NodeList jdbcPs = ((Element) jdbc.item(0)).getElementsByTagName("property");

Map<String, String> jdbcConfig = new HashMap<String, String>();
for (int i = 0; i < jdbcPs.getLength(); i++) {
jdbcConfig.put(((Element) jdbcPs.item(i)).getElementsByTagName("name").item(0).getFirstChild().getNodeValue(), ((Element) jdbcPs.item(i))
.getElementsByTagName("value").item(0).getFirstChild().getNodeValue());
}

return jdbcConfig;
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

public static OR_class class_config(String className) {

try {
Document document = getDoc();
NodeList classList = document.getElementsByTagName("class");
OR_class orCla = new OR_class();

for (int i = 0; i < classList.getLength(); i++) {
Element cla = (Element) classList.item(i);
if (cla.getAttribute("name").equals(className)) {
orCla.setName(cla.getAttribute("name"));
orCla.setName(cla.getAttribute("table"));
NodeList propertyLi = cla.getElementsByTagName("property");
List<List<String>> propertyList = new ArrayList<List<String>>();
for (int j = 0; j < propertyLi.getLength(); j++) {
List<String> property = new ArrayList<String>();

property.add(((Element) propertyLi.item(j)).getElementsByTagName("name").item(0).getFirstChild().getNodeValue());
property.add(((Element) propertyLi.item(j)).getElementsByTagName("column").item(0).getFirstChild().getNodeValue());
property.add(((Element) propertyLi.item(j)).getElementsByTagName("type").item(0).getFirstChild().getNodeValue());
property.add(((Element) propertyLi.item(j)).getElementsByTagName("lazy").item(0).getFirstChild().getNodeValue());

propertyList.add(property);
}
orCla.setPropertyList(propertyList);
return orCla;
}
}

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

private static Document getDoc() throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
Document document = documentBuilder.parse(new File(path));
return document;
}
}


相对应的OR_class类

package sc.ustc.bean;

import java.util.List;

public class OR_class {

private String name;
private String table;
private List<List<String>> propertyList;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTable() {
return table;
}

public void setTable(String table) {
this.table = table;
}

public List<List<String>> getPropertyList() {
return propertyList;
}

public void setPropertyList(List<List<String>> propertyList) {
this.propertyList = propertyList;
}

}


Conversation将对象操作映射为数据表操作

Conversation类实现了将对象操作映射为数据表操作,实现了数据操作的CRUD 方法,将对象操作解释成翻译成数据库操作,对映射数据进行持久化。

package sc.ustc.dao;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import sc.ustc.bean.OR_class;

public class Conversation {

public static Object selectObj(Object o) {

Class<?> cla = o.getClass();
OR_class orC = Configuration.class_config(cla.getName());
String table = orC.getTable();
List<List<String>> propertyList = orC.getPropertyList();

// 得到object的属性及值
List<List<String>> fieldValueList = new ArrayList<List<String>>();
for (int i = 0; i < propertyList.size(); i++) {

try {
Field field = cla.getDeclaredField(propertyList.get(i).get(0));
field.setAccessible(true);
String fieldString = (String) field.get(o);
if (fieldString != null) {
List<String> sList = new ArrayList<String>();
sList.add(propertyList.get(i).get(1));
sList.add(fieldString);
fieldValueList.add(sList);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

// 构造查询sql
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select ");
for (int i = 0; i < fieldValueList.size(); i++) {
if (fieldValueList.get(i).get(3).equals("false")) {
sqlBuilder.append(fieldValueList.get(i).get(1) + ",");
}
}
sqlBuilder.deleteCharAt(sqlBuilder.length() - 1);
sqlBuilder.append(" from " + table + " where ");
for (int i = 0; i < fieldValueList.size(); i++) {
if (fieldValueList.get(i).get(3).equals("false")) {
sqlBuilder.append(fieldValueList.get(i).get(0) + " = ? and ");
}
}
sqlBuilder.delete(sqlBuilder.length() - 5, sqlBuilder.length() - 1);

try {
// 连接DB
Connection conn = getConnection();
// select
PreparedStatement ps = conn.prepareStatement(sqlBuilder.toString());
for (int i = 0; i < fieldValueList.size(); i++) {
ps.setString(i + 1, fieldValueList.get(i).get(1));
}
return ps.executeQuery();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}

return null;
}

public static boolean deleteObjById(Object o) {

try {

// 通过反射机制得到object的id属性
Class<?> cla = o.getClass();
Field id = cla.getDeclaredField("id");
id.setAccessible(true);
String idString = (String) id.get(o);

// 解析xml文件得到对应的数据库表
OR_class orC = Configuration.class_config(cla.getName());
String table = orC.getTable();
List<List<String>> propertyList = orC.getPropertyList();
String tableId = null;
for (int i = 0; i < propertyList.size(); i++) {
if (propertyList.get(i).get(0).equals("id")) {
tableId = propertyList.get(i).get(1);
}
}

// 连接DB
Connection conn = getConnection();

// delete
String sql = "delete from " + table + " where " + tableId + " = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, idString);
return ps.executeUpdate() == 1;

} catch (SQLException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

return false;
}

private static Connection getConnection() throws ClassNotFoundException, SQLException {
Map<String, String> jdbcMap = Configuration.jdbc_config();
Class.forName(jdbcMap.get("driver"));
Connection conn = DriverManager.getConnection(jdbcMap.get("url"), jdbcMap.get("userName"), jdbcMap.get("password"));
return conn;
}
}


or-mapping.xml

定义jdbc的连接配置信息以及对象与数据库表之间的映射关系。

<?xml version="1.0" encoding="UTF-8"?>
<OR-Mappings>
<jdbc>
<property>
<name>driver</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>url</name>
<value>jdbc:mysql://localhost:3306/user</value>
</property>
<property>
<name>userName</name>
<value>root</value>
</property>
<property>
<name>password</name>
<value>null</value>
</property>
</jdbc>
<class name="water.ustc.bean.UserBean" table="useraccount">
<property>
<name>id</name>
<column>id</column>
<type>String</type>
<lazy>false</lazy>
</property>
<property>
<name>userName</name>
<column>name</column>
<type>String</type>
<lazy>false</lazy>
</property>
<property>
<name>userPass</name>
<column>password</column>
<type>String</type>
<lazy>false</lazy>
</property>
<property>
<name>imfor</name>
<column>imfor</column>
<type>water.ustc.bean.Imformation</type>
<lazy>true</lazy>
</property>
</class>
</OR-Mappings>


实现对象属性 lazy – loading

为需要延迟加载的对象新建代理类LazyLoadProxy实现LazyLoader接口,这样,只有当获取该对象属性时才会通过该代理类回调方法进行对象初始化。不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化了(在CGLib的实现中只要去访问该对象内属性的getter方法,就会自动触发代理类回调)。

UserBean.java代码

UserBean,对应表useraccount,定义了其属性以及相应的方法,例如根据用户名和密码进行登录验证。

package water.ustc.bean;

import java.sql.ResultSet;

import net.sf.cglib.proxy.Enhancer;
import sc.ustc.tool.LazyLoadProxy;
import water.ustc.dao.UserDao;

public class UserBean {

private String id;
private String userName;
private String userPass;
private Imformation imfor;

public UserBean(String id) {
this.id = id;
this.imfor = inforProxy();
}

@SuppressWarnings("static-access")
Imformation inforProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Imformation.class);
return (Imformation) enhancer.create(Imformation.class, new LazyLoadProxy(this));
}

public UserBean(String userName, String userPass) {
this.userName = userName;
this.userPass = userPass;
}

public boolean signIn() {

UserDao userDao = new UserDao();

ResultSet rs = (ResultSet) userDao.selectObj(this);
if (rs != null) {
return true;
}
return false;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getUserPass() {
return userPass;
}

public void setUserPass(String userPass) {
this.userPass = userPass;
}
}


当调用Conversation中查询方法时,对于lazy属性设置成true的数据库中的coloum会跳过,只有在使用此属性时才会由代理进行加载。

Conversation部分代码如下:

// 构造查询sql
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select ");
for (int i = 0; i < fieldValueList.size(); i++) {
if (fieldValueList.get(i).get(3).equals("false")) {
sqlBuilder.append(fieldValueList.get(i).get(1) + ",");
}
}
sqlBuilder.deleteCharAt(sqlBuilder.length() - 1);
sqlBuilder.append(" from " + table + " where ");
for (int i = 0; i < fieldValueList.size(); i++) {
if (fieldValueList.get(i).get(3).equals("false")) {
sqlBuilder.append(fieldValueList.get(i).get(0) + " = ? and ");
}
}
sqlBuilder.delete(sqlBuilder.length() - 5, sqlBuilder.length() - 1);


LazyLoadProxy.java

package sc.ustc.tool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;

import net.sf.cglib.proxy.LazyLoader;
import sc.ustc.dao.Configuration;
import water.ustc.bean.Imformation;
import water.ustc.bean.UserBean;

public class LazyLoadProxy implements LazyLoader {

private UserBean userBean;

public Object loadObject() throws Exception {

Map<String, String> jdbcMap = Configuration.jdbc_config();
Class.forName(jdbcMap.get("driver"));
Connection conn = DriverManager.getConnection(jdbcMap.get("url"), jdbcMap.get("userName"), jdbcMap.get("password"));

String sqlString = "select * from useraccount where id = ?";
PreparedStatement ps = conn.prepareStatement(sqlString);
ps.setString(1, userBean.getId());

ResultSet rs = ps.executeQuery();

while (rs.next()) {
return rs.getObject(4, Imformation.class);
}
return null;

}

public LazyLoadProxy(UserBean userBean) {

this.userBean = userBean;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mybatis mysql 架构
相关文章推荐