Mybatis實(shí)現(xiàn)動(dòng)態(tài)增刪改查功能的示例代碼
一、Mybatis 流程簡(jiǎn)介
最近在看 Mybatis 的源碼,大致了解整個(gè)框架流程后便手寫了一個(gè)特別簡(jiǎn)單的SimpMybatis的小Demo,來鞏固這整個(gè)框架的學(xué)習(xí)。下圖是我所畫的框架大致執(zhí)行流程:

💊對(duì)上圖分析后得出結(jié)論:
1.Mybatis 的配置文件分為兩種,且這兩個(gè)配置文件會(huì)被封裝到 Configuration 中
- 主配置文件(MybatisConfig.xml):配置 jdbc 等環(huán)境信息,全局唯一;
- 映射文件(xxxMapper.xml):配置多個(gè) Sql ,可有多個(gè)。
2.通過 Mybatis 配置文件得到 SqlSessionFactory ;
3.通過 SqlSessionFactory 得到 SqlSession,它就相當(dāng)于 Request 請(qǐng)求;
4.SqlSession 調(diào)用底層的 Executor 執(zhí)行器來操作數(shù)據(jù)庫,同時(shí)執(zhí)行器有兩類實(shí)現(xiàn)
- 基本實(shí)現(xiàn)
- 帶有緩存功能的實(shí)現(xiàn)
5.解析傳入的參數(shù),對(duì)其進(jìn)行封裝,執(zhí)行并返回結(jié)果;
以上就是我梳理的 Mybatis 大致流程,看似簡(jiǎn)單,卻很精妙。
二、手寫簡(jiǎn)化版 Mybatis 設(shè)計(jì)思路
2.1 簡(jiǎn)化后的思路

2.2 讀取 XML 文件,建立連接
從圖中可以看出,MyConfig 負(fù)責(zé)與人交互。待讀取xml后,將屬性和連接數(shù)據(jù)庫的操作封裝在 MyConfig 對(duì)象中供后面的組件調(diào)用。本項(xiàng)目將使用 dom4j 來讀取xml文件,它具有性能優(yōu)異和非常方便使用的特點(diǎn)。
2.3 創(chuàng)建SqlSession,搭建 Configuration 和 Executor 之間的橋梁
從流程圖中的箭頭可以看出,MySqlSession 的成員變量中必須得有 MyExecutorImpl 和 MyConfig 去集中做調(diào)配。一個(gè)Session僅擁有一個(gè)對(duì)應(yīng)的數(shù)據(jù)庫連接。類似于一個(gè)前段請(qǐng)求Request,它負(fù)責(zé)直接調(diào)用對(duì)應(yīng) execute(sql) 來做 CRUD 操作。
2.4 創(chuàng)建 MyExecutor,封裝 JDBC 操作數(shù)據(jù)庫
MyExecutor 是一個(gè)執(zhí)行器,負(fù)責(zé)SQL語句的生成和查詢緩存的維護(hù),也就是 Jdbc 的代碼將在這里完成,不過本文只實(shí)現(xiàn)了單表,查詢緩存并未實(shí)現(xiàn)。
2.5 創(chuàng)建 MySqlSessionProxy,使用動(dòng)態(tài)代理生成 Mapper 對(duì)象
只是希望對(duì)指定的接口生成一個(gè)對(duì)象,使得執(zhí)行它的時(shí)候能運(yùn)行一句 sql,而接口無法直接調(diào)用方法,所以這里使用動(dòng)態(tài)代理生成對(duì)象,在執(zhí)行時(shí)還是回到 MySqlSession 中調(diào)用查詢,最終由 MyExecutorImpl 做 JDBC查詢。這樣設(shè)計(jì)是為了單一職責(zé),可擴(kuò)展性更強(qiáng)。
三、實(shí)現(xiàn)自己的Mybatis
這次會(huì)將其打成 Jar 包,并將其導(dǎo)入項(xiàng)目實(shí)現(xiàn),做一個(gè) Mybatis 的還原。
工程文件及目錄:

3.1 導(dǎo)入兩個(gè)所需 Jar 包:數(shù)據(jù)庫連接和XML解析
Maven 導(dǎo)入如下:
<!-- https://mvnrepository.com/artifact/org.dom4j/dom4j --> <!-- xml解析 --> <dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.3</version> </dependency> <!-- Mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>
3.2 創(chuàng)建 MyConfig 類,對(duì)兩大 XML 配置文件進(jìn)行解析,并建立連接
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 12:17
*/
public class MyConfig {
/**
* 啟動(dòng)應(yīng)用程序類加載器
*/
private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
/**
* 數(shù)據(jù)庫建立連接
* @return 返回?cái)?shù)據(jù)庫連接對(duì)象
*
*/
public Connection build() {
// Mybatis主配置文件名
String resource = "mybatis-config.xml";
// 獲取文件根節(jié)點(diǎn)
Element root = parseXML(resource);
// 獲取文件對(duì)應(yīng)的信息
Map<String, String> jdbcMap = parseNodes(root);
try {
Class.forName(jdbcMap.get("driverClassName"));
} catch (ClassNotFoundException e) {
throw new RuntimeException("驅(qū)動(dòng)器未找到,請(qǐng)重新檢查!");
}
Connection connect = null;
try {
connect = DriverManager.getConnection(jdbcMap.get("url"), jdbcMap.get("username"), jdbcMap.get("password"));
} catch (SQLException throwables) {
throw new RuntimeException("數(shù)據(jù)庫連接錯(cuò)誤,請(qǐng)檢查路徑、用戶名、密碼是否輸入正確!");
}
return connect;
}
/**
* 解析數(shù)據(jù)庫配置文件
* @param resource 數(shù)據(jù)庫配置文件路徑
* @return 獲取到的文件根節(jié)點(diǎn)
*/
public static Element parseXML(String resource) {
try {
// 返回用于讀取指定資源的輸入流
InputStream stream = loader.getResourceAsStream(resource);
// 使用dom4j解析XML
SAXReader reader = new SAXReader();
// 使用SAX從給定流中讀取文件
Document doc = reader.read(stream);
// 獲取文件的根節(jié)點(diǎn)
return doc.getRootElement();
} catch (DocumentException e) {
throw new RuntimeException("解析 XML 時(shí)發(fā)生錯(cuò)誤!" + resource);
}
}
/**
* 解析主xml文件標(biāo)簽節(jié)點(diǎn)
* @param node 配置文件根節(jié)點(diǎn)
* @return 返回從配置文件中拿到的開啟數(shù)據(jù)庫對(duì)應(yīng)值
*/
private Map<String, String> parseNodes(Element node) {
// 判斷根標(biāo)簽名稱
if (!node.getName().equals("database")) {
throw new RuntimeException("數(shù)據(jù)庫配置文件根標(biāo)簽名稱必須為【database】");
}
// 存放配置文件取得的值
Map<String, String> map = new HashMap<String, String>();
map.put("driverClassName", null);
map.put("url", null);
map.put("username", null);
map.put("password", null);
// 讀取property的屬性內(nèi)容
for (Element item : node.elements()) {
// 獲取標(biāo)簽中存放的值,并刪除其前導(dǎo)和結(jié)尾的空格
String value = getValue(item);
// 獲取標(biāo)簽中 name 的名稱
String name = item.attributeValue("name");
// 如果name或value為空則有對(duì)應(yīng)值未輸入
if (name == null || "".equals(value)) {
throw new RuntimeException("[database]: <property> 中應(yīng)該包含名稱和值");
}
switch (name) {
case "driverClassName" : map.put("driverClassName", value); break;
case "url" : map.put("url", value); break;
case "username" : map.put("username", value); break;
case "password" : map.put("password", value); break;
default: throw new RuntimeException("[database]: <property> 中有未知屬性");
}
}
return map;
}
/**
* 獲取property屬性中的值
* @param node 配置文件根節(jié)點(diǎn)
* @return 如果有value值,則讀取;沒有設(shè)置value,則讀取內(nèi)容
*/
private static String getValue(Element node) {
return node.hasContent() ? node.getText().trim() : node.attributeValue("value").trim();
}
/**
*
* @param path
* @return
*/
@SuppressWarnings(value = "rawtypes")
public MappingBean readMapper(String path) {
MappingBean bean = new MappingBean();
try {
InputStream stream = loader.getResourceAsStream(path);
SAXReader reader = new SAXReader();
Document doc = reader.read(stream);
Element root = doc.getRootElement();
// 把mapper節(jié)點(diǎn)的nameSpace值存為接口名
bean.setInterfaceName(root.attributeValue("nameSpace").trim());
// 用來存儲(chǔ)方法的List
List<Mapping> list = new ArrayList<Mapping>();
//遍歷根節(jié)點(diǎn)下所有子節(jié)點(diǎn)
for(Iterator rootIter = root.elementIterator(); rootIter.hasNext();) {
// 存儲(chǔ)一條方法的信息
Mapping fun = new Mapping();
Element e = (Element) rootIter.next();
String sqlType = e.getName().trim();
String funcName = e.attributeValue("id").trim();
String sql = e.getText().trim();
String resultType = e.attributeValue("resultType").trim();
fun.setSqlType(sqlType);
fun.setFuncName(funcName);
Object newInstance = null;
try {
newInstance = Class.forName(resultType).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e1) {
e1.printStackTrace();
}
fun.setResultType(newInstance);
fun.setSql(sql);
list.add(fun);
}
bean.setList(list);
} catch (DocumentException e) {
e.printStackTrace();
}
return bean;
}
/**
* 解析mapper映射xml文件
* @param element mapper文件路徑
* @return
*/
public MappingBean parseMapper(Element element) {
MappingBean bean = new MappingBean();
String namespace = element.attributeValue("namespace");
if (namespace == null) {
throw new RuntimeException("映射文件namespace不存在");
}
bean.setInterfaceName(namespace);
List<Mapping> list = new ArrayList<>();
Iterator<Element> it = element.elementIterator();
while (it.hasNext()) {
Element ele=(Element) it.next();
Mapping mapping =new Mapping();
String funcName =ele.attributeValue("id");
if (funcName==null){
throw new RuntimeException("mapper映射文件中id不存在");
}
String sqlType = ele.getName();
String paramType = ele.attributeValue("parameterType");
String resultType=ele.attributeValue("resultType");
String sql=ele.getText().trim();
mapping.setFuncName(funcName);
mapping.setSqlType(sqlType);
mapping.setParameterType(paramType);
mapping.setSql(sql);
Object object=null;
try {
object=Class.forName(resultType).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
mapping.setResultType(object);
list.add(mapping);
}
bean.setList(list);
return bean;
}
}
⚡由 MyConfig類 代碼可以得知:
- Mybatis 主配置類名稱必須為:
mybatis-config.xml; - mybatis-config.xml 的根標(biāo)簽必須為:
<database></database>; - Mapper.xml 必須包括:
namespace; - Sql 是否有返回值都應(yīng)包括:
resultType(個(gè)人偷懶,沒做判斷);... ...
3.3 MySqlSession 代理
MySqlSession 肯定不會(huì)自己去執(zhí)行,因?yàn)椴荒軐懰浪允褂脛?dòng)態(tài)代理來使代理類去實(shí)現(xiàn)具體方法。
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 12:52
*/
public class MySqlSession {
private final MyExcutor excutor= new MyExcutorImpl();
private final MyConfig config = new MyConfig();
public <T> T selectValue(Mapping statement, List<Object> parameter){
return excutor.queryValue(statement, parameter);
}
public <T> T selectNull(Mapping statement){
return excutor.queryNull(statement);
}
public int deleteValue(Mapping statement, List<Object> parameter) {
return excutor.deleteValue(statement, parameter);
}
public int updateValue(Mapping statement, List<Object> parameter) {
return excutor.updateValue(statement, parameter);
}
public int insertValue(Mapping mapping, List<Object> parameter) {
return excutor.insertValue(mapping, parameter);
}
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> clas){
//動(dòng)態(tài)代理調(diào)用
return (T) Proxy.newProxyInstance(clas.getClassLoader(),new Class[]{clas},
new MySqlSessionProxy(config,this));
}
}
編寫代理類,把mapper映射文件解析進(jìn)來
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 12:55
*/
public class MySqlSessionProxy implements InvocationHandler {
private MyConfig config;
private MySqlSession sqlSession;
public MySqlSessionProxy(MyConfig config, MySqlSession sqlSession) {
this.config = config;
this.sqlSession = sqlSession;
}
@Override
public Object invoke(Object proxy, Method method,Object[] args) {
String name = method.getDeclaringClass().getName();
String mapperName = name.substring(name.lastIndexOf(".")+1);
MappingBean bean=config.parseMapper(MyConfig.parseXML(mapperName+".xml"));
if (bean!=null && (bean.getList()!=null && bean.getList().size()>0)){
for (Mapping mapping : bean.getList()){
if (mapping.getFuncName().equals(method.getName())) {
// 判斷是否為查詢語句
if ("select".equals(mapping.getSqlType().toLowerCase())) {
System.out.println("執(zhí)行查詢方法:" + mapping.getSql());
if (args!=null) {
System.out.println("參數(shù):"+ Arrays.toString(args));
return sqlSession.selectValue(mapping, Arrays.asList(args));
} else {
System.out.println("參數(shù):null");
return sqlSession.selectNull(mapping);
}
}
// 判斷是否為刪除語句
if ("delete".equals(mapping.getSqlType().toLowerCase())){
System.out.println("執(zhí)行查詢方法:"+mapping.getSql());
System.out.println("參數(shù):"+ Arrays.toString(args));
return sqlSession.deleteValue(mapping, Arrays.asList(args));
}
// 判斷是否為更新語句
if ("update".equals(mapping.getSqlType().toLowerCase())) {
System.out.println("執(zhí)行查詢方法:"+mapping.getSql());
System.out.println("參數(shù):"+ Arrays.toString(args));
return sqlSession.updateValue(mapping, Arrays.asList(args));
}
// 判斷是否為插入語句
if ("insert".equals(mapping.getSqlType().toLowerCase())) {
System.out.println("執(zhí)行查詢方法:" + mapping.getSql());
System.out.println("參數(shù):" + Arrays.toString(args));
return sqlSession.insertValue(mapping, Arrays.asList(args));
}
}
}
}
return null;
}
}
⚡注意:通過上段代碼可知,映射文件必須和接口名稱保持一致。
3.4 創(chuàng)建對(duì)應(yīng)實(shí)體類和XML映射文件Sql實(shí)體類
a. 接口實(shí)體類
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 12:38
*/
public class MappingBean {
/**
* 接口名
*/
private String interfaceName;
/**
* 接口下所有方法
*/
private List<Mapping> list;
// setter、getter略
}
b. 映射文件中 Sql 的實(shí)體類
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 12:38
*/
public class Mapping {
private String sqlType;
private String funcName;
private String sql;
private Object resultType;
private String parameterType;
// setter、getter略
}
3.5 創(chuàng)建 MyExcutor 接口以及實(shí)現(xiàn)類
MyExcutor 接口
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 12:42
*/
public interface MyExcutor {
// 無參查詢
<T> T queryNull(Mapping mapping);
// 有參查詢
<T> T queryValue(Mapping mapping, List<Object> params);
// 刪除
int deleteValue(Mapping mapping, List<Object> params);
// 更新
int updateValue(Mapping mapping, List<Object> params);
// 插入
int insertValue(Mapping mapping, List<Object> params);
}
MyExcutorImpl 實(shí)現(xiàn)類
這里通過反射將結(jié)果轉(zhuǎn)換成對(duì)象
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 12:42
*/
public class MyExcutorImpl implements MyExcutor {
private MyConfig config = new MyConfig();
@Override
public <T> T queryNull(Mapping mapping) {
Connection conn = config.build();
PreparedStatement preparedStatement;
ResultSet resultSet;
Object obj;
List<Object> list = new ArrayList<>();
try {
preparedStatement=conn.prepareStatement(mapping.getSql());
if (mapping.getResultType() == null){
throw new RuntimeException("返回的映射結(jié)果不能為空!");
}
resultSet = preparedStatement.executeQuery();
int row = 0;
ResultSetMetaData rd = resultSet.getMetaData();
while (resultSet.next()){
obj=resultToObject(resultSet,mapping.getResultType());
row++;
list.add(obj);
}
System.out.println("記錄行數(shù):"+row);
} catch (SQLException e) {
e.printStackTrace();
}
return (T) list;
}
@Override
public <T> T queryValue(Mapping mapping, List<Object> params) {
Connection conn = config.build();
PreparedStatement preparedStatement;
ResultSet resultSet;
Object obj;
List<Object> list = new ArrayList<>();
try {
preparedStatement=conn.prepareStatement(mapping.getSql());
for (int i=0; i<params.size(); i++) {
preparedStatement.setString(i+1, params.get(i).toString());
}
if (mapping.getResultType() == null){
throw new RuntimeException("返回的映射結(jié)果不能為空!");
}
resultSet = preparedStatement.executeQuery();
int row = 0;
ResultSetMetaData rd = resultSet.getMetaData();
while (resultSet.next()){
obj=resultToObject(resultSet,mapping.getResultType());
row++;
list.add(obj);
}
System.out.println("記錄行數(shù):"+row);
} catch (SQLException e) {
e.printStackTrace();
}
return (T) list;
}
@Override
public int deleteValue(Mapping mapping, List<Object> params) {
Connection conn = config.build();
int rows = 0;
PreparedStatement preparedStatement=null;
try {
preparedStatement = conn.prepareStatement(mapping.getSql());
for (int i=0; i<params.size(); i++) {
preparedStatement.setString(i+1, params.get(i).toString());
}
rows = preparedStatement.executeUpdate();
if (rows != 0) {
System.out.println("刪除成功,受影響行數(shù):"+rows);
} else {
System.out.println("刪除失敗,數(shù)據(jù)庫無相應(yīng)數(shù)據(jù)...");
}
} catch (SQLException e) {
e.printStackTrace();
}
return rows;
}
@Override
public int updateValue(Mapping mapping, List<Object> params) {
Connection conn = config.build();
int rows = 0;
PreparedStatement preparedStatement=null;
try {
preparedStatement = conn.prepareStatement(mapping.getSql());
for (int i=0; i<params.size(); i++) {
preparedStatement.setString(i+1, params.get(i).toString());
}
rows = preparedStatement.executeUpdate();
if (rows != 0) {
System.out.println("修改成功,受影響行數(shù):"+rows);
} else {
System.out.println("修改失敗,數(shù)據(jù)庫無相應(yīng)數(shù)據(jù)...");
}
} catch (SQLException e) {
e.printStackTrace();
}
return rows;
}
@Override
public int insertValue(Mapping mapping, List<Object> params) {
Connection conn = config.build();
int rows = 0;
PreparedStatement preparedStatement=null;
try {
preparedStatement = conn.prepareStatement(mapping.getSql());
for (int i=0; i<params.size(); i++) {
preparedStatement.setString(i+1, params.get(i).toString());
}
try {
rows = preparedStatement.executeUpdate();
if (rows != 0) {
System.out.println("插入成功,受影響行數(shù):"+rows);
} else {
System.out.println("插入失敗...");
}
} catch (SQLException throwables) {
throw new RuntimeException("插入重復(fù) \"Key\" 值數(shù)據(jù)");
}
} catch (SQLException e) {
e.printStackTrace();
}
return rows;
}
private <T> T resultToObject(ResultSet rs, Object object) {
Object obj=null;
try {
Class<?> cls = object.getClass();
/*
這里為什么要通過class再new一個(gè)對(duì)象?
因?yàn)槿绻籲ew一個(gè)新的對(duì)象,每次返回的都是形參上的object,
而這個(gè)object都是同一個(gè),會(huì)導(dǎo)致list列表后面覆蓋前面值。
*/
obj=cls.newInstance();
//獲取結(jié)果集元數(shù)據(jù)(獲取此 ResultSet 對(duì)象的列的編號(hào)、類型和屬性。)
ResultSetMetaData rd=rs.getMetaData();
for (int i = 0; i < rd.getColumnCount(); i++) {
//獲取列名
String columnName=rd.getColumnLabel(i+1);
//組合方法名
String methodName="set"+columnName.substring(0, 1).toUpperCase()+columnName.substring(1);
//獲取列類型
int columnType=rd.getColumnType(i+1);
Method method=null;
switch(columnType) {
case java.sql.Types.VARCHAR:
case java.sql.Types.CHAR:
method=cls.getMethod(methodName, String.class);
method.invoke(obj, rs.getString(columnName));
break;
case java.sql.Types.INTEGER:
method=cls.getMethod(methodName, Integer.class);
method.invoke(obj, rs.getInt(columnName));
break;
default:
break;
}
}
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException | SQLException e) {
e.printStackTrace();
}
return (T) obj;
}
}
四、打包測(cè)試
4.1 將其打成 Jar 包

4.2 創(chuàng)建一個(gè)Maven項(xiàng)目,因?yàn)樾枰獙?dǎo)入對(duì)應(yīng)的包
<!-- https://mvnrepository.com/artifact/org.dom4j/dom4j --> <!-- xml解析 --> <dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.3</version> </dependency> <!-- Mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <!-- 自己寫的Mybatis,首先要將其放入本地倉庫 --> <dependency> <groupId>top.kk233</groupId> <artifactId>SimpMybatis</artifactId> <version>1.0.0</version> </dependency>
⚡Maven導(dǎo)入本地Jar包方法自行百度,這里就不贅述。
4.3 創(chuàng)建數(shù)據(jù)庫
這里提供一個(gè)我測(cè)試的,你們可以自行創(chuàng)建其他的
CREATE DATABASE IF NOT EXISTS `test`; USE `test`; CREATE TABLE `user` ( `id` INT ( 10 ) NOT NULL, `sex` VARCHAR ( 2 ) NOT NULL, `password` VARCHAR ( 255 ) DEFAULT NULL, `username` VARCHAR ( 255 ) DEFAULT NULL, PRIMARY KEY ( `id` ) ) ENGINE = INNODB AUTO_INCREMENT = 2 DEFAULT CHARSET = utf8; INSERT INTO `test`.`user` ( `id`, `sex`, `password`, `username` ) VALUES ( 1, '男', '12344', '五六' ), ( 2, '女', '12643', '張三' ), ( 3, '男', '1245453', '李四' );
4.4 創(chuàng)建實(shí)體類
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 16:17
*/
public class User {
private Integer id;
private String sex;
private String password;
private String username;
// setter、getter略
}
4.5 創(chuàng)建 UserMapper 接口
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 16:17
*/
public interface UserMapper {
List<User> getUsers();
List<User> getUserBySexAndName(String sex, String username);
int deleteUserById(Integer id);
int updateUserByName(String username, String password);
int insertUser(int id, String sex, String password, String username);
}
4.6 創(chuàng)建 UserMapper.xml 映射文件
<?xml version="1.0" encoding="UTF-8"?> <mapper namespace="top.kk233.mapper.UserMapper"> <select id="getUsers" resultType="top.kk233.pojo.User"> SELECT * FROM user </select> <select id="getUserBySexAndName" resultType="top.kk233.pojo.User"> select * from user where sex=? and username=? </select> <delete id="deleteUserById" resultType="top.kk233.pojo.User"> delete from user where id=? </delete> <update id="updateUserByName" resultType="top.kk233.pojo.User"> update user set password=? where username=? </update> <insert id="insertUser" resultType="top.kk233.pojo.User"> insert into user values(?,?,?,?) </insert> </mapper>
4.7 創(chuàng)建 mybatis-config.xml 數(shù)據(jù)庫配置文件
<?xml version="1.0" encoding="UTF-8"?> <database> <property name="driverClassName">com.mysql.jdbc.Driver</property> <property name="url">jdbc:mysql://localhost:3306/test?useSSL=false</property> <property name="username">root</property> <property name="password">124760</property> </database>
4.8 創(chuàng)建啟動(dòng)類測(cè)試
/**
* @author Kenelm
* @version 1.0
* @date 2020/11/22 16:24
*/
public class app {
public static void main(String[] args) {
MySqlSession sql = new MySqlSession();
UserMapper mapper = sql.getMapper(UserMapper.class);
List<User> users = mapper.getUsers();
users.forEach(System.out::println);
System.out.println("==========================");
List<User> users1 = mapper.getUserBySexAndName("女", "張三");
users1.forEach(System.out::println);
System.out.println("==========================");
mapper.deleteUserById(1);
System.out.println("==========================");
mapper.updateUserByName("五六", "女");
System.out.println("==========================");
mapper.insertUser(10, "男", "123123", "五七");
}
}
4.9 測(cè)試結(jié)果

👌測(cè)試成功,這就是本人所手寫的Mybatis,雖然比較簡(jiǎn)單,但還是學(xué)習(xí)到了很多東西。
💥項(xiàng)目放在 Gitee 上有需要自行下載,覺得可以還請(qǐng)點(diǎn)個(gè)Star
到此這篇關(guān)于Mybatis實(shí)現(xiàn)動(dòng)態(tài)增刪改查功能的示例代碼的文章就介紹到這了,更多相關(guān)mybatis增刪改查內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
實(shí)例解析Java關(guān)于static的作用
只要是有學(xué)過Java的都一定知道static,也一定能多多少少說出一些作用和注意事項(xiàng)。文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
java網(wǎng)絡(luò)爬蟲連接超時(shí)解決實(shí)例代碼
這篇文章主要介紹了java網(wǎng)絡(luò)爬蟲連接超時(shí)解決的問題,分享了一則使用httpclient解決連接超時(shí)的Java爬蟲實(shí)例代碼,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
SpringMVC對(duì)自定義controller入?yún)㈩A(yù)處理方式
這篇文章主要介紹了SpringMVC對(duì)自定義controller入?yún)㈩A(yù)處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
jdk8使用stream實(shí)現(xiàn)兩個(gè)list集合合并成一個(gè)(對(duì)象屬性的合并)
本文主要介紹了jdk8使用stream實(shí)現(xiàn)兩個(gè)list集合合并成一個(gè)(對(duì)象屬性的合并),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
看動(dòng)畫學(xué)算法之Java實(shí)現(xiàn)doublyLinkedList
這篇文章主要介紹Java實(shí)現(xiàn)doublyLinkedList,LinkedList:doublyLinkedList相對(duì)比較復(fù)雜,今天就來簡(jiǎn)單學(xué)習(xí)一下doublyLinkedList的基本操作和概,感興趣的小伙伴可以參考下面具體文章內(nèi)容2021-10-10
springmvc字符編碼過濾器CharacterEncodingFilter的使用
這篇文章主要介紹了springmvc字符編碼過濾器CharacterEncodingFilter的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2021-08-08
Java簡(jiǎn)單實(shí)現(xiàn)調(diào)用命令行并獲取執(zhí)行結(jié)果示例
這篇文章主要介紹了Java簡(jiǎn)單實(shí)現(xiàn)調(diào)用命令行并獲取執(zhí)行結(jié)果,結(jié)合實(shí)例形式分析了Java調(diào)用ping命令并獲取執(zhí)行結(jié)果相關(guān)操作技巧,需要的朋友可以參考下2018-08-08

