第⼀步:IDEA中创建模块
模块:godbatis(创建普通的Java Maven模块,打包方式jar),引入相关依赖
<?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>org.god.ibatis</groupId>
<artifactId>godbatis</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
第二步:资源工具类,方便获取指向配置文件的输入流
package org.god.core;
import java.io.InputStream;
public class Resources {
public Resources() {
}
public static InputStream getResourcesAsStream(String config){
return Thread.currentThread().getContextClassLoader().getResourceAsStream(config);
}
}
第三步:定义SqlSessionFactoryBuilder类
package org.god.core;
import java.io.InputStream;
public class SqlSessionFactoryBuilder {
/**
* 创建构建器对象
*/
public SqlSessionFactoryBuilder() {
}
/**
* 获取SqlSessionFactory对象
* 该⽅法主要功能是:读取godbatis核⼼配置⽂件,并构建SqlSessionFactory对象
* @param inputStream 指向核⼼配置⽂件的输⼊流
* @return SqlSessionFactory对象
*/
public SqlSessionFactory build(InputStream inputStream){
// 解析配置⽂件,创建数据源对象
// 解析配置⽂件,创建事务管理器对象
// 解析配置⽂件,获取所有的SQL映射对象
// 将以上信息封装到SqlSessionFactory对象中
// 返回
return null;
}
}
第四步:分析SqlSessionFactory类中有哪些属性
事务管理器 GodJDBCTransaction
SQL映射对象集合 Map<String, GodMappedStatement>
第五步:定义GodJDBCTransaction
事务管理器最好是定义⼀个接口,然后每⼀个具体的事务管理器都实现这个接口。
package org.god.core;
import java.sql.Connection;
public interface TransactionManager {
void commit();
void rollback();
void close();
void openConnection();
Connection getConnection();
}
package org.god.core;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class GodJDBCTransaction implements TransactionManager{
private Connection conn;
private DataSource dataSource;
private boolean autoCommit;
public GodJDBCTransaction(DataSource dataSource, boolean autoCommit) {
this.dataSource = dataSource;
this.autoCommit = autoCommit;
}
@Override
public void commit() {
try {
conn.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public void rollback() {
try {
conn.rollback();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public void close() {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public void openConnection() {
try {
this.conn = dataSource.getConnection();
this.conn.setAutoCommit(this.autoCommit);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public Connection getConnection() {
return conn;
}
}
第六步:事务管理器中需要数据源,定义GodUNPOOLEDDataSource
package org.god.core;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
public class GodUNPOOLEDDataSource implements javax.sql.DataSource{
private String driver;
private String url;
private String username;
private String password;
public GodUNPOOLEDDataSource(String driver, String url, String username, String password) {
//this.driver = driver;
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
this.url = url;
this.username = username;
this.password = password;
}
@Override
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}
第七步:定义GodMappedStatement
package org.god.core;
public class GodMappedStatement {
private String sqlId;
private String resultType;
private String sql;
private String parameterType;
private String sqlType;
public String getSqlId() {
return sqlId;
}
public void setSqlId(String sqlId) {
this.sqlId = sqlId;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public String getParameterType() {
return parameterType;
}
public void setParameterType(String parameterType) {
this.parameterType = parameterType;
}
public String getSqlType() {
return sqlType;
}
public void setSqlType(String sqlType) {
this.sqlType = sqlType;
}
public GodMappedStatement(String sqlId, String resultType, String sql, String parameterType, String sqlType) {
this.sqlId = sqlId;
this.resultType = resultType;
this.sql = sql;
this.parameterType = parameterType;
this.sqlType = sqlType;
}
@Override
public String toString() {
return "GodMappedStatement{" +
"sqlId='" + sqlId + '\'' +
", resultType='" + resultType + '\'' +
", sql='" + sql + '\'' +
", parameterType='" + parameterType + '\'' +
", sqlType='" + sqlType + '\'' +
'}';
}
}
第八步:完善SqlSessionFactory类
package org.god.core;
import java.util.Map;
public class SqlSessionFactory {
private TransactionManager transactionManager;
private Map<String,GodMappedStatement> mappedStatements;
public TransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public Map<String, GodMappedStatement> getMappedStatements() {
return mappedStatements;
}
public void setMappedStatements(Map<String, GodMappedStatement> mappedStatements) {
this.mappedStatements = mappedStatements;
}
public SqlSessionFactory(TransactionManager transactionManager, Map<String, GodMappedStatement> mappedStatements) {
this.transactionManager = transactionManager;
this.mappedStatements = mappedStatements;
}
}
第九步:完善SqlSessionFactoryBuilder中的build方法
package org.god.core;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.sql.DataSource;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class SqlSessionFactoryBuilder {
/**
* 创建构建器对象
*/
public SqlSessionFactoryBuilder() {
}
/**
* 获取SqlSessionFactory对象
* 该⽅法主要功能是:读取godbatis核⼼配置⽂件,并构建SqlSessionFactory对象
*
* @param inputStream 指向核⼼配置⽂件的输⼊流
* @return SqlSessionFactory对象
*/
public SqlSessionFactory build(InputStream inputStream) throws DocumentException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(inputStream);
Element environmentsElt = (Element) document.selectSingleNode("/configuration/environments");
String defaultEnv = environmentsElt.attributeValue("default");
Element environmentElt = (Element) document.selectSingleNode("/configuration/environments/environment[@id='" + defaultEnv + "']");
// 解析配置⽂件,创建数据源对象
Element dataSourceElt = environmentElt.element("dataSource");
DataSource dataSource = getDataSource(dataSourceElt);
// 解析配置⽂件,创建事务管理器对象
Element transactionManagerElt = environmentElt.element("transactionManager");
TransactionManager transactionManager = getTransactionManager(transactionManagerElt, dataSource);
// 解析配置⽂件,获取所有的SQL映射对象
Element mappers = environmentsElt.element("mappers");
Map<String, GodMappedStatement> mappedStatements = getMappedStatements(mappers);
// 将以上信息封装到SqlSessionFactory对象中
SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(transactionManager, mappedStatements);
// 返回
return sqlSessionFactory;
}
private Map<String, GodMappedStatement> getMappedStatements(Element mappers) {
Map<String, GodMappedStatement> mappedStatements = new HashMap<>();
mappers.elements().forEach((Element mapperElt) -> {
try {
String resource = mapperElt.attributeValue("resource");
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(Resources.getResourcesAsStream(resource));
Element mapper = (Element) document.selectSingleNode("/mapper");
String namespace = mapper.attributeValue("namespace");
mapper.elements().forEach((Element sqlMapper) -> {
String sqlId = sqlMapper.attributeValue("id");
String sql = sqlMapper.getTextTrim();
String parameterType = sqlMapper.attributeValue("parameterType");
String resultType = sqlMapper.attributeValue("resultType");
String sqlType = sqlMapper.getName().toLowerCase();
// 封装GodMappedStatement对象
GodMappedStatement godMappedStatement = new GodMappedStatement(sqlId, resultType, sql, parameterType, sqlType);
mappedStatements.put(namespace + "." + sqlId, godMappedStatement);
});
} catch (DocumentException e) {
throw new RuntimeException(e);
}
});
return mappedStatements;
}
private TransactionManager getTransactionManager(Element transactionManagerElt, DataSource dataSource) {
String type = transactionManagerElt.attributeValue("type").toUpperCase();
TransactionManager transactionManager = null;
if ("JDBC".equals(type)) {
// 使⽤JDBC事务
transactionManager = new GodJDBCTransaction(dataSource, false
);
} else if ("MANAGED".equals(type)) {
// 事务管理器是交给JEE容器的
}
return transactionManager;
}
private DataSource getDataSource(Element dataSourceElt) {
// 获取所有数据源的属性配置
Map<String, String> dataSourceMap = new HashMap<>();
//Element propertyElt = (Element) beanNode;
dataSourceElt.elements().forEach(( Element propertyElt) -> {
dataSourceMap.put(propertyElt.attributeValue("name"), propertyElt.attributeValue("value"));
});
String dataSourceType = dataSourceElt.attributeValue("type").toUpperCase();
DataSource dataSource = null;
if ("POOLED".equals(dataSourceType)) {
} else if ("UNPOOLED".equals(dataSourceType)) {
dataSource = new GodUNPOOLEDDataSource(dataSourceMap.get("driver"), dataSourceMap.get("url"), dataSourceMap.get("username"), dataSourceMap.get("password"));
} else if ("JNDI".equals(dataSourceType)) {
}
return dataSource;
}
}
第十步:在SqlSessionFactory中添加openSession方法
public SqlSession openSession(){
transactionManager.openConnection();
SqlSession sqlSession=new SqlSession(transactionManager,mappedStatements);
return sqlSession;
}
第十一步:编写SqlSession类中commit rollback close方法
ackage org.god.core;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
public class SqlSession {
private TransactionManager transactionManager;
private Map<String,GodMappedStatement> mappedStatements;
public SqlSession(TransactionManager transactionManager, Map<String,GodMappedStatement> mappedStatements) {
this.transactionManager = transactionManager;
this.mappedStatements = mappedStatements;
}
public void commit(){
try {
transactionManager.getConnection().commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void rollback(){
try {
transactionManager.getConnection().rollback();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void close(){
try {
transactionManager.getConnection().close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
第十二步:编写SqlSession类中的insert,delete,select,update方法(略)
public int insert(String sqlId, Object obj) {
GodMappedStatement godMappedStatement = mappedStatements.get(sqlId);
Connection connection = transactionManager.getConnection();
// 获取sql语句
// insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
String godbatisSql = godMappedStatement.getSql();
// insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)
String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
// 重点⼀步
Map<Integer, String> map = new HashMap<>();
int index = 1;
while (godbatisSql.indexOf("#") >= 0) {
int beginIndex = godbatisSql.indexOf("#") + 2;
int endIndex = godbatisSql.indexOf("}");
map.put(index++, godbatisSql.substring(beginIndex, endIndex).trim(
));
godbatisSql = godbatisSql.substring(endIndex + 1);
}
final PreparedStatement ps;
try {
ps = connection.prepareStatement(sql);
// 给?赋值
map.forEach((k, v) -> {
try {
// 获取java实体类的get⽅法名
String getMethodName = "get" + v.toUpperCase().charAt(0) +
v.substring(1);
Method getMethod = obj.getClass().getDeclaredMethod(getMethodName);
ps.setString(k, getMethod.invoke(obj).toString());
} catch (Exception e) {
throw new RuntimeException(e);
}
});
int count = ps.executeUpdate();
ps.close();
return count;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Object selectOne(String sqlId, Object parameterObj){
GodMappedStatement godMappedStatement = mappedStatements.get(sqlId);
Connection connection = transactionManager.getConnection();
// 获取sql语句
String godbatisSql = godMappedStatement.getSql();
String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
// 执⾏sql
PreparedStatement ps = null;
ResultSet rs = null;
Object obj = null;
try {
ps = connection.prepareStatement(sql);
ps.setString(1, parameterObj.toString());
rs = ps.executeQuery();
if (rs.next()) {
// 将结果集封装对象,通过反射
String resultType = godMappedStatement.getResultType();
Class<?> aClass = Class.forName(resultType);
Constructor<?> con = aClass.getDeclaredConstructor();
obj = con.newInstance();
// 给对象obj属性赋值
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String columnName = rsmd.getColumnName(i);
String setMethodName = "set" + columnName.toUpperCase().charAt(0) + columnName.substring(1);
Method setMethod = aClass.getDeclaredMethod(setMethodName,
aClass.getDeclaredField(columnName).getType());
setMethod.invoke(obj, rs.getString(columnName));
}
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
try {
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return obj;
}
第十三步:测试类及配置文件
import com.god.pojo
public class Car {
private Long id;
private String carNum;
private String brand;
private Double guidePrice;
private String produceTime;
private String carType;
@Override
public String toString() {
return "Car{" +
"id=" + id +
", carNum='" + carNum + '\'' +
", brand='" + brand + '\'' +
", guidePrice=" + guidePrice +
", produceTime='" + produceTime + '\'' +
", carType='" + carType + '\'' +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCarNum() {
return carNum;
}
public void setCarNum(String carNum) {
this.carNum = carNum;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Double getGuidePrice() {
return guidePrice;
}
public void setGuidePrice(Double guidePrice) {
this.guidePrice = guidePrice;
}
public String getProduceTime() {
return produceTime;
}
public void setProduceTime(String produceTime) {
this.produceTime = produceTime;
}
public String getCarType() {
return carType;
}
public void setCarType(String carType) {
this.carType = carType;
}
public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
this.id = id;
this.carNum = carNum;
this.brand = brand;
this.guidePrice = guidePrice;
this.produceTime = produceTime;
this.carType = carType;
}
}
import org.junit.Test;
import prg.god.pojo.Car
public class testYourbatis {
@Test
public void testInsert() {
SqlSession sqlSession = null;
try {
// 1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("Yourbatis-config.xml"));
// 3.创建SqlSession对象
sqlSession = sqlSessionFactory.openSession();
// 4.执⾏SQL
Car car = new Car(null, "111", "宝⻢X7", 70.3, "2010-10-11", "燃油⻋");
int count = sqlSession.insert("insertCar", car);
System.out.println("更新了⼏条记录:" + count);
// 5.提交
sqlSession.commit();
} catch (Exception e) {
// 回滚
if (sqlSession != null) {
sqlSession.rollback();
}
e.printStackTrace();
} finally {
// 6.关闭
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Test
public void testSelectOne() {
SqlSession sqlSession = null;
try {
// 1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 3.创建SqlSession对象
sqlSession = sqlSessionFactory.openSession();
// 4.执⾏SQL
Car car = (Car) sqlSession.selectOne("selectCarByCarNum", "111");
System.out.println(car);
// 5.提交
sqlSession.commit();
} catch (Exception e) {
// 回滚
if (sqlSession != null) {
sqlSession.rollback();
}
e.printStackTrace();
} finally {
// 6.关闭
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/po
wernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<mappers>
<mapper resource="sqlmapper.xml"/>
</mappers>
</environments>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="car">
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_ty
pe) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carTyp
e})
</insert>
<select id="selectCarByCarNum" resultType="com.god.pojo.
Car">
select id,car_num carNum,brand,guide_price guidePrice,produce_tim
e produceTime,car_type carType from t_car where car_num = #{carNum}
</select>
</mapper>
本项目是基于自学b站中动力节点老杜的mybatis视频,笔记仅供学习参考使用。