简易版Mybatis框架
自己的Mybatis框架设计图
依照Mybatis的框架执行原理,实现简易版的Mybatis框架
数据库建User表:
建立如下的实体表,用于增删改查
CREATE TABLE `NewTable
` (
`id
` int(20) NOT NULL AUTO_INCREMENT ,
`username
` varchar(100) CHARACTER SET utf8
COLLATE utf8_general_ci
NULL DEFAULT NULL ,
`password
` varchar(100) CHARACTER SET utf8
COLLATE utf8_general_ci
NULL DEFAULT NULL ,
`gender
` int(1) NULL DEFAULT NULL ,
`age
` int(2) NULL DEFAULT NULL ,
`idcard
` int(20) NULL DEFAULT NULL ,
`phone
` int(15) NULL DEFAULT NULL ,
PRIMARY KEY (`id
`)
);
新建Maven项目引入需要的依赖
引入Mysql驱动依赖、Dom4j(解析Xml)、FastJson(Json工具)
<dependencies>
<dependency>
<groupId>mysql
</groupId>
<artifactId>mysql-connector-java
</artifactId>
<version>5.1.47
</version>
</dependency>
<dependency>
<groupId>dom4j
</groupId>
<artifactId>dom4j
</artifactId>
<version>1.1
</version>
</dependency>
<dependency>
<groupId>com.alibaba
</groupId>
<artifactId>fastjson
</artifactId>
<version>1.2.62
</version>
</dependency>
</dependencies>
数据源配置文件:mysqlconfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<database>
<property name="driverClassName">com.mysql.jdbc.Driver
</property>
<property name="url">jdbc:mysql://localhost:3306/test
</property>
<property name="username">root
</property>
<property name="password">root
</property>
</database>
连接数据库和解析Mapper的工具类:MyConfiguration
public class MyConfiguration {
private ClassLoader classLoader
=ClassLoader
.getSystemClassLoader();
private Logger logger
= LoggerFactory
.getLogger(MyConfiguration
.class);
public Connection
getDataSourceInfo(){
try{
InputStream inputStream
=classLoader
.getResourceAsStream("mysqlconfig.xml");
SAXReader reader
=new SAXReader();
Document document
=reader
.read(inputStream
);
Element element
=document
.getRootElement();
logger
.info("==========数据库配置信息读取成功!");
return getConnection(element
);
}catch (Exception e
){
logger
.error(e
.getMessage());
return null
;
}
}
private Connection
getConnection(Element element
) {
String driverClassName
=null
;
String url
=null
;
String username
=null
;
String password
=null
;
if(!"database".equals(element
.getName())){
throw new RuntimeException("数据库xml配置读取错误!");
}
List
<Object> property
= element
.elements("property");
for (Object o
: property
) {
Element el
= (Element
) o
;
String name
= el
.attribute(0).getValue();
String value
= (String
) el
.getData();
if(name
==null
|| value
==null
){
throw new RuntimeException("property信息读取失败!");
}
switch (name
){
case "driverClassName":
driverClassName
=value
;
break;
case "url":
url
=value
;
break;
case "username":
username
=value
;
break;
case "password":
password
=value
;
break;
default:
throw new RuntimeException("==========数据库信息有错误!");
}
}
try {
Connection connection
=null
;
Class
.forName(driverClassName
);
logger
.info("==========连接数据库获取驱动成功!");
connection
= DriverManager
.getConnection(url
,username
,password
);
logger
.info("==========连接数据库成功!");
return connection
;
}catch (Exception e
){
logger
.error(e
.getMessage());
return null
;
}
}
public MapperBean
readMapper(String path
){
MapperBean mapperBean
=new MapperBean();
try{
InputStream inputStream
=classLoader
.getResourceAsStream(path
);
SAXReader saxReader
=new SAXReader();
Document document
=saxReader
.read(inputStream
);
Element root
=document
.getRootElement();
mapperBean
.setInterfaceName(root
.attributeValue("namespace").trim());
List
<Function> list
=new ArrayList<>();
for(Iterator iterator
=root
.elementIterator();iterator
.hasNext();){
Function function
=new Function();
Element element
= (Element
) iterator
.next();
String sqlType
=element
.getName().trim();
String functionNam
=element
.attributeValue("id").trim();
String sql
=element
.getText().trim();
String resultType
=null
;
Object newinstance
=null
;
if(null
!=element
.attributeValue("resultType")){
resultType
=element
.attributeValue("resultType");
try{
newinstance
=Class
.forName(resultType
).newInstance();
}catch (Exception e
){
logger
.error(e
.getMessage());
}
function
.setResultType(resultType
);
}
function
.setFunctionName(functionNam
);
function
.setSqlType(sqlType
);
function
.setSql(sql
);
list
.add(function
);
}
mapperBean
.setList(list
);
}catch (Exception e
){
return null
;
}
return mapperBean
;
}
}
存放Mapper类信息的实体类:MapperBean、省略setget方法
public class MapperBean {
private String interfaceName
;
private List
<Function> list
;
public MapperBean(){}
public MapperBean(String interfaceName
, List
<Function> list
) {
this.interfaceName
= interfaceName
;
this.list
= list
;
}
@Override
public String
toString() {
return "MapperBean{" +
"interfaceName='" + interfaceName
+ '\'' +
", list=" + list
+
'}';
}
}
存放Mapper.xml的信息的实体类:Function
public class Function {
private String sqlType
;
private String functionName
;
private String sql
;
private String resultType
;
private String parameterType
;
public Function(){}
public Function(String sqlType
, String functionName
, String sql
, String resultType
, String parameterType
) {
this.sqlType
= sqlType
;
this.functionName
= functionName
;
this.sql
= sql
;
this.resultType
= resultType
;
this.parameterType
= parameterType
;
}
}
MyMapperProxy代理类完成读取的UserMapper.xml中方法与真实方法校验,并调用执行对应的方法
public class MyMapperProxy implements InvocationHandler {
private MysqlSession mysqlSession
;
private MyConfiguration myConfiguration
;
public MyMapperProxy(MysqlSession mysqlSession
, MyConfiguration myConfiguration
) {
this.mysqlSession
= mysqlSession
;
this.myConfiguration
= myConfiguration
;
}
@Override
public Object
invoke(Object proxy
, Method method
, Object
[] args
) throws Throwable
{
MapperBean mapperBean
= myConfiguration
.readMapper("UserMapper.xml");
if (!method
.getDeclaringClass().getName().equals(mapperBean
.getInterfaceName())) {
return null
;
}
List
<Function> list
= mapperBean
.getList();
if (!CollectionUtils
.isEmpty(list
)) {
for (Function x
: list
) {
if (judge(method
, x
, "selectById")) {
return mysqlSession
.selectOne(x
.getSql(), String
.valueOf(args
[0]));
}
if (judge(method
, x
, "deleteById")) {
mysqlSession
.deleteOne(x
.getSql(), String
.valueOf(args
[0]));
}
if (judge(method
, x
, "insert")) {
mysqlSession
.insertOne(x
.getSql(), String
.valueOf(args
[0]));
}
if (judge(method
, x
, "updateById")) {
mysqlSession
.updateOne(x
.getSql(), String
.valueOf(args
[0]));
}
}
}
return null
;
}
private boolean judge(Method method
, Function x
, String methodId
) {
return method
.getName().equals(x
.getFunctionName()) && x
.getFunctionName().equals(methodId
);
}
}
MysqlSession类,其中getMapper()动态代理的方式获取对象
public class MysqlSession {
private Logger logger
= LoggerFactory
.getLogger(MysqlSession
.class);
private MyConfiguration myConfiguration
=new MyConfiguration();
private Excutor excutor
=new ExcutorImpl();
public <T> T
selectOne(String statment
,Object parameter
){
logger
.info("我是query的SqlSession!");
return excutor
.query(statment
,parameter
);
}
public void insertOne(String statment
,Object parmeter
){
logger
.info("我是save的SqlSession!");
excutor
.save(statment
,parmeter
);
}
public void updateOne(String statment
,Object parmeter
){
logger
.info("我是modify的SqlSession!");
excutor
.modify(statment
,parmeter
);
}
public void deleteOne(String statment
,Object parmeter
){
logger
.info("我是remove的SqlSession!");
excutor
.remove(statment
,parmeter
);
}
public <T> T
getMapper(Class
<T> clazz
){
logger
.info("已经通过代理获取对象!");
return (T
) Proxy
.newProxyInstance(clazz
.getClassLoader(), new Class[]{clazz
}, new MyMapperProxy(this, myConfiguration
));
}
}
增删改查底层接口:Excutor
public interface Excutor {
<T> T
query(String statement
,Object parameter
);
void save(String statement
,Object parameter
);
void modify(String statement
,Object parameter
);
void remove(String statement
,Object parameter
);
}
增删改查底层接口实现:ExcutorImpl
连接数据库,Jdbc方式进行怎删改查操作
public class ExcutorImpl implements Excutor {
private Logger logger
= LoggerFactory
.getLogger(ExcutorImpl
.class);
private MyConfiguration myConfiguration
=new MyConfiguration();
Connection connection
= myConfiguration
.getDataSourceInfo();
@Override
public <T> T
query(String statement
, Object parameter
) {
try{
PreparedStatement preparedStatement
= connection
.prepareStatement(statement
);
preparedStatement
.setString(1,parameter
.toString());
ResultSet resultSet
= preparedStatement
.executeQuery();
User user
=new User();
while (resultSet
.next()){
user
.setId(resultSet
.getInt("id"));
user
.setUsername(resultSet
.getString("username"));
user
.setPassword(resultSet
.getString("password"));
user
.setGender(resultSet
.getInt("gender"));
user
.setAge(resultSet
.getInt("age"));
user
.setIdcard(resultSet
.getInt("idcard"));
user
.setPhone(resultSet
.getInt("phone"));
}
logger
.info("遍历结果集完成!");
return (T
)user
;
}catch (Exception e
){
logger
.error("查询结果报错"+e
.getMessage());
return null
;
}
}
@Override
public void save(String statement
, Object parameter
) {
try {
connection
.setAutoCommit(false);
PreparedStatement preparedStatement
= connection
.prepareStatement(statement
);
User user
= JSON
.parseObject(String
.valueOf(parameter
),User
.class);
preparedStatement
.setInt(1,user
.getId());
preparedStatement
.setString(2,user
.getUsername());
preparedStatement
.setString(3,user
.getPassword());
preparedStatement
.setInt(4,user
.getGender());
preparedStatement
.setInt(5,user
.getAge());
preparedStatement
.setInt(6,user
.getIdcard());
preparedStatement
.setInt(7,user
.getPhone());
preparedStatement
.execute();
comit(connection
);
logger
.info("保存成功!");
} catch (Exception e
) {
logger
.error("保存失败"+e
.getMessage());
rollBack(connection
);
}
}
@Override
public void modify(String statement
, Object parameter
) {
try {
PreparedStatement preparedStatement
= connection
.prepareStatement(statement
);
User user
= JSON
.parseObject(String
.valueOf(parameter
),User
.class);
preparedStatement
.setInt(3,user
.getId());
preparedStatement
.setString(1,user
.getUsername());
preparedStatement
.setString(2,user
.getPassword());
preparedStatement
.execute();
comit(connection
);
logger
.info("修改成功!");
} catch (SQLException e
) {
logger
.error("修改失败"+e
.getMessage());
rollBack(connection
);
}
}
@Override
public void remove(String statement
, Object parameter
) {
try {
PreparedStatement preparedStatement
= connection
.prepareStatement(statement
);
preparedStatement
.setString(1,parameter
.toString());
preparedStatement
.execute();
logger
.info("删除成功!");
} catch (SQLException throwables
) {
throwables
.printStackTrace();
}
}
private void comit(Connection connection
){
try {
connection
.commit();
logger
.error("事物提交成功!");
}catch (Exception e
){
logger
.error("事物提交失败!"+e
.getMessage());
}
}
private void rollBack(Connection connection
){
try{
connection
.rollback();
logger
.info("事物回滚成功!");
} catch (Exception e
){
logger
.info("事物回滚失败!"+e
.getMessage());
}
}
}
User实体类
public class User {
private int id
;
private String username
;
private String password
;
private int gender
;
private int age
;
private int idcard
;
private int phone
;
@Override
public String
toString() {
return "User{" +
"id=" + id
+
", username='" + username
+ '\'' +
", password='" + password
+ '\'' +
", gender=" + gender
+
", age=" + age
+
", idcard=" + idcard
+
", phone=" + phone
+
'}';
}
}
UserMapper类
public interface UserMapper {
User
selectById(String id
);
void insert(Object user
);
void updateById(Object user
);
void deleteById(String id
);
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="com.li.mybatisconfig.mapper.UserMapper">
<select id="selectById" resultType="com.li.mybatisconfig.entity.User">
select * from user where id=?
</select>
<delete id="deleteById" >
delete from user where id=?
</delete>
<insert id="insert">
insert into user (id,username,password,gender,age,idcard,phone) values(?,?,?,?,?,?,?)
</insert>
<update id="updateById">
update user set username=?,password=? where id=?
</update>
</mapper>
增删改查测试类:MybatisTestRunner
public class MybatisTestRunner {
MysqlSession mysqlSession
=new MysqlSession();
UserMapper mapper
=mysqlSession
.getMapper(UserMapper
.class);
@Test
public void findById(){
User user
= mapper
.selectById("1");
System
.out
.println(user
);
}
@Test
public void insert(){
User user
=new User();
user
.setId(2);
user
.setUsername("test1");
user
.setPassword("test1");
mapper
.insert(JSON
.toJSON(user
));
}
@Test
public void deleteById(){
mapper
.deleteById("1");
}
@Test
public void update(){
User user
=new User();
user
.setId(2);
user
.setUsername("test2");
user
.setPassword("test2");
mapper
.updateById(JSON
.toJSON(user
));
}
}
查询接口方法运行日志打印如下
很Nice 感觉Mybatis 不是那么难 哈哈 哈哈!
代码详情见https://gitee.com/Marlon_Brando/back.git