主è¦å®ç°ï¼å°è£ SqlSessionå°æ§è¡å¨+Mapperæ¥å£åMapper.xml+MapperBean+å¨æ代çMapperçæ¹æ³
1.Mybatisæ´ä½æ¶æåæ
对ä¸å¾ç解读ï¼
1ï¼mybatis çæ ¸å¿é ç½®æ件
mybatis-config.xmlï¼è¿è¡å ¨å±é ç½®ï¼å ¨å±åªè½æä¸ä¸ªè¿æ ·çé ç½®æ件
â XxxMapper.xml é ç½®å¤ä¸ªSQLï¼å¯ä»¥æå¤ä¸ª XxxMapper.xml é ç½®æ件
2ï¼éè¿ mybatis-config.xml é ç½®æ件å¾å° SqlSessionFactory
3ï¼éè¿ SqlSessionFactory å¾å° SqlSessionï¼ç¨ SqlSession å°±å¯ä»¥æä½æ°æ®äº
4ï¼SqlSession åºå±æ¯ Executor(æ§è¡å¨)ï¼æ两个éè¦çå®ç°ç±»
5ï¼MappedStatement æ¯éè¿ XxxMapper.xml æ¥å®ä¹çï¼ç¨æ¥çæ statement 对象
6ï¼åæ°è¾å ¥æ§è¡å¹¶è¾åºç»æéï¼æ éå¨æå¤æåæ°ç±»åååæ°ä¸æ ä½ç½®ï¼ä¸èªå¨å°ç»æéæ å°ä¸ºJava对象
2.æ建å¼åç¯å¢
ï¼1ï¼å建maven项ç®
ï¼2ï¼å¨pom.xml ä¸å¼å ¥å¿ è¦çä¾èµ
<!--æå®ç¼è¯å¨/source/targetççæ¬--><properties> <project.build.sourdeEncoding>UTF-8</project.build.sourdeEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <java.version>1.8</java.version></properties> <!--å¼å
¥å¿
è¦çä¾èµ--><dependencies> <!--dom4j--> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <!--lombok-ç®åentity/javabean/pojo çå¼å--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency></dependencies>
ï¼3ï¼å建æ°æ®åºå表
-- å建æ°æ®åºCREATE DATABASE `li_mybatis`;USE `li_mybatis`;-- å建monster表CREATE TABLE `monster`(`id` INT NOT NULL AUTO_INCREMENT,`age` INT NOT NULL,`birthday` DATE DEFAULT NULL,`email` VARCHAR(255) NOT NULL,`gender` TINYINT NOT NULL,-- 1 maleï¼0 female`name` VARCHAR(255) NOT NULL,`salary` DOUBLE NOT NULL,PRIMARY KEY(`id`))CHARSET=utf8-- insertINSERT INTO `monster` VALUES(NULL,200,'2000-11-11','[email protected]',1,'çéç',8888);
3.设计æè·¯
解读ï¼
-
ä¼ ç»çæ¹å¼æä½æ°æ®åº
1ï¼å¾å° MySession 对象
2ï¼è°ç¨ MyExecutor çæ¹æ³å®ææä½
3ï¼MyExecutor çè¿æ¥æ¯ä» MyConfiguration è·å
-
Mybatis æä½æ°æ®åºçæ¹å¼
1ï¼å¾å° MySession 对象
2ï¼ä¸ç´æ¥è°ç¨ MyExecutor çæ¹æ³
3ï¼èæ¯éè¿ MyMapperProxy è·å Mapper 对象
4ï¼è°ç¨ Mapper çæ¹æ³ï¼å®æ对æ°æ®åºçæä½
5ï¼Mapper æç»è¿æ¯å¨æ代çæ¹å¼ï¼ä½¿ç¨ MyExecutor çæ¹æ³å®ææä½
6ï¼è¿éæ¯è¾éº»ç¦çå°±æ¯ MyMapperProxy çå¨æ代çæºå¶å¦ä½å®ç°
4.ä»»å¡é¶æ®µ1
é¶æ®µ1ä»»å¡ï¼éè¿é ç½®æ件ï¼è·åæ°æ®åºè¿æ¥
4.1åæ
4.2代ç å®ç°
ï¼1ï¼å¨src ç resourcesç®å½ä¸å建 my-config.xmlï¼æ¨¡æåçç mybatis é ç½®æ件
<?xml version="1.0" encoding="UTF-8" ?><database> <!--é
ç½®è¿æ¥æ°æ®åºçä¿¡æ¯--> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/li_mybatis? useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/></database>
ï¼2ï¼å建 MyConfiguration ç±»ï¼ç¨æ¥è¯»åxmlæ件ï¼å»ºç«è¿æ¥
å 为è¿ééç¹æ¯å®ç° Mybatis çåºå±æºå¶ï¼ä¸ºäºç®åæä½ï¼å°±ä¸ä½¿ç¨æ°æ®åºè¿æ¥æ± äºï¼ç´æ¥ä½¿ç¨åççconnection è¿æ¥
package com.li.limybatis.sqlsession; import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader; import java.io.InputStream;import java.sql.Connection;import java.sql.DriverManager; /** * @author æ * @version 1.0 * ç¨æ¥è¯»åxmlæ件ï¼å»ºç«è¿æ¥ */public class MyConfiguration { //å±æ§-ç±»çå è½½å¨ private static ClassLoader loader = ClassLoader.getSystemClassLoader(); //读åxmlæ件并å¤ç public Connection build(String resource) { Connection connection = null; try { //å
å è½½é
ç½®æ件 my-config.xmlï¼è·å对åºçInputStream InputStream stream = loader.getResourceAsStream(resource); //解æ my-config.xmlæ件 SAXReader reader = new SAXReader(); Document document = reader.read(stream); //è·å xmlæ件çæ ¹å
ç´ <database> Element root = document.getRootElement(); System.out.println("root=" + root); //æ ¹æ®root解æï¼è·åConnection connection = evalDataSource(root); } catch (Exception e) { e.printStackTrace(); } return connection; } //解æ my-config.xml çä¿¡æ¯ï¼å¹¶è¿å Connection private Connection evalDataSource(Element node) { if (!"database".equals(node.getName())) { throw new RuntimeException("rootèç¹åºè¯¥æ¯<database>"); } //è¿æ¥DBçå¿
è¦åæ° String driverClassName = null; String url = null; String username = null; String password = null; //éånodeä¸çåèç¹ï¼è·åå
¶å±æ§å¼ for (Object item : node.elements("property")) { //iå°±æ¯å¯¹åºç propertyèç¹ Element i = (Element) item; //propertyèç¹ç nameå±æ§çå¼ String name = i.attributeValue("name"); //propertyèç¹ç valueå±æ§çå¼ String value = i.attributeValue("value"); //å¤æå¼æ¯å¦ä¸ºç©º if (name == null || value == null) { throw new RuntimeException("propertyèç¹æ²¡æ设置nameævalueå±æ§ï¼"); } switch (name) { case "url": url = value; break; case "username": username = value; break; case "driverClassName": driverClassName = value; break; case "password": password = value; break; default: throw new RuntimeException("å±æ§å没æå¹é
å°.."); } } //è·åè¿æ¥ Connection connection = null; try { Class.forName(driverClassName); connection = DriverManager.getConnection(url, username, password); } catch (Exception e) { e.printStackTrace(); } return connection; }}
5.ä»»å¡é¶æ®µ2
é¶æ®µ2ä»»å¡ï¼éè¿å®ç°æ§è¡å¨æºå¶ï¼å¯¹æ°æ®è¡¨è¿è¡æä½
5.1åæ
æ们æ对æ°æ®åºçæä½å°è£ å°ä¸å¥Executoræºå¶ä¸ï¼ç¨åºå ·ææ´å¥½çæå±æ§ï¼ç»ææ´å æ¸ æ°ãè¿éæ们å å®ç°ä¼ ç»çæ¹å¼è¿æ¥æ°æ®åºï¼å³éè¿MyExecutorç´æ¥æä½æ°æ®åºã
5.2代ç å®ç°
ï¼1ï¼çæ entity ç±» Monster.java
package com.li.entity; import lombok.*; import java.util.Date; /** * @author æ * @version 1.0 * Monsterç±»å monsterææ å°å
³ç³» * * 注解说æï¼ * @Getter ç»ææå±æ§çæ getteræ¹æ³ * @Setter ç»ææå±æ§çæ setteræ¹æ³ * @ToString çætoStringæ¹æ³ * @NoArgsConstructor çæä¸ä¸ªæ åæé å¨ * @AllArgsConstructor çæä¸ä¸ªå
¨åæé å¨ * @Data ä¼çæä¸è¿°é¤äºæ å/å
¨åæé å¨çæææ¹æ³ï¼æ¤å¤è¿ä¼çæequals,hashCodeçæ¹æ³ */@Getter@Setter@ToString@NoArgsConstructor@AllArgsConstructorpublic class Monster { private Integer id; private Integer age; private String name; private String email; private Date birthday; private double salary; private Integer gender;}
ï¼2ï¼Executor æ¥å£
package com.li.limybatis.sqlsession; /** * @author æ * @version 1.0 */public interface Executor { //æ³åæ¹æ³ public <T> T query(String statement, Object parameter);}
ï¼3ï¼æ§è¡å¨å®ç°ç±» MyExecutor.java
package com.li.limybatis.sqlsession; import com.li.entity.Monster; import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException; /** * @author æ * @version 1.0 */public class MyExecutor implements Executor { private MyConfiguration myConfiguration = new MyConfiguration(); /** * æ ¹æ®sqlï¼è¿åæ¥è¯¢ç»æ * * @param sql * @param parameter * @param <T> * @return */ @Override public <T> T query(String sql, Object parameter) { //è·åè¿æ¥å¯¹è±¡ Connection connection = getConnection(); //æ¥è¯¢è¿åçç»æé ResultSet set = null; PreparedStatement pre = null; try { //æ建PreparedStatement对象 pre = connection.prepareStatement(sql); //设置åæ°ï¼å¦æåæ°å¤ï¼å¯ä»¥ä½¿ç¨æ°ç»å¤ç pre.setString(1, parameter.toString()); //æ¥è¯¢è¿åçç»æé set = pre.executeQuery(); //æç»æéçæ°æ®å°è£
å°å¯¹è±¡ä¸-monster //说æï¼è¿éåäºç®åå¤çï¼è®¤ä¸ºè¿åçç»æå°±æ¯ä¸ä¸ªmonsterè®°å½ï¼å®åçåæ³åºè¯¥ä½¿ç¨åå°æºå¶ Monster monster = new Monster(); //éåç»æé,å°æ°æ®å°è£
å°monsterå¯¹è±¡ä¸ while (set.next()) { monster.setId(set.getInt("id")); monster.setName(set.getString("name")); monster.setEmail(set.getString("email")); monster.setAge(set.getInt("age")); monster.setGender(set.getInt("gender")); monster.setBirthday(set.getDate("birthday")); monster.setSalary(set.getDouble("salary")); } return (T) monster; } catch (Exception e) { e.printStackTrace(); } finally { try { if (set != null) { set.close(); } if (pre != null) { pre.close(); } if (connection != null) { connection.close(); } } catch (Exception e) { e.printStackTrace(); } } return null; } //ç¼åæ¹æ³ï¼éè¿myConfiguration对象è¿åè¿æ¥ private Connection getConnection() { Connection connection = myConfiguration.build("my-config.xml"); return connection; }}
ï¼4ï¼è¿è¡æµè¯
@Testpublic void query() { Executor executor = new MyExecutor(); Monster monster = (Monster) executor.query("select * from monster where id = ?", 1); System.out.println("monster--" + monster);}
æµè¯ç»æï¼
6.ä»»å¡é¶æ®µ3
é¶æ®µ3ä»»å¡ï¼å°æ§è¡å¨å°è£ å°SqlSession
6.1代ç å®ç°
ï¼1ï¼å建 MySqlSession ç±»ï¼å°æ§è¡å¨å°è£ å°SqlSessionä¸ã
package com.li.limybatis.sqlsession; /** * @author æ * @version 1.0 * MySqlSessionï¼æ建Configuration(è¿æ¥)åExecutorä¹é´çæ¡¥æ¢ */public class MySqlSession { //æ§è¡å¨ private Executor executor = new MyExecutor(); //é
ç½® private MyConfiguration myConfiguration = new MyConfiguration(); //ç¼åæ¹æ³selectOneï¼è¿åä¸æ¡è®°å½ public <T> T selectOne(String statement,Object parameter){ return executor.query(statement, parameter); }}
ï¼2ï¼æµè¯
@Testpublic void selectOne() { MySqlSession mySqlSession = new MySqlSession(); Monster monster = (Monster) mySqlSession.selectOne("select * from monster where id=?", 1); System.out.println("monster=" + monster);}
æµè¯ç»æï¼
7.ä»»å¡é¶æ®µ4&5
é¶æ®µ4ä»»å¡ï¼å¼åMapperæ¥å£åMapper.xml
é¶æ®µ5ä»»å¡ï¼å¼ååMapperæ¥å£ç¸æ å°çMapperBean
ï¼1ï¼Mapperæ¥å£
package com.li.mapper; import com.li.entity.Monster; /** * @author æ * @version 1.0 * MonsterMapperï¼å£°æ对æ°æ®åºçcrudæ¹æ³ */public interface MonsterMapper { //æ¥è¯¢æ¹æ³ public Monster getMonsterById(Integer id); }
ï¼2ï¼Mapper.xmlæ件
<?xml version="1.0" encoding="UTF-8" ?><mapper namespace="com.li.mapper.MonsterMapper"> <!--å®ç°é
ç½®æ¥å£æ¹æ³getMonsterById--> <select id="getMonsterById" resultType="com.li.entity.Monster"> select * from monster where id = ? </select></mapper>
ï¼3ï¼Function.javaï¼ç¨äºè®°å½Mapper.xmlæ件å®ç°çæ¹æ³ä¿¡æ¯
package com.li.limybatis.config; import lombok.Getter;import lombok.Setter; /** * @author æ * @version 1.0 * Functionï¼è®°å½å¯¹åº Mapper.xmlçæ¹æ³ä¿¡æ¯ */@Getter@Setter@ToStringpublic class Function { private String sqlType;//sqlç±»åï¼å¦selectï¼updateï¼insertï¼delete private String funcName;//æ¹æ³å private String sql;//æ§è¡çsqlè¯å¥ private Object resultType;//è¿åç±»å private String parameterType;//åæ°ç±»å}
ï¼4ï¼MapperBean.javaï¼ä½ç¨æ¯è¯»åMapperæ¥å£å¯¹åºçMapper.xmlï¼å°è¯¥xmlæ件æ¹æ³ä¿¡æ¯å°è£ å°MapperBeanä¸ã
package com.li.limybatis.config; import lombok.Getter;import lombok.Setter; import java.util.List; /** * @author æ * @version 1.0 * MapperBeanï¼å°æ们çMapperä¿¡æ¯ï¼è¿è¡å°è£
*/@Setter@Getter@ToStringpublic class MapperBean { private String interfaceName;//æ¥å£å //æ¥å£ä¸çæææ¹æ³ public List<Function> functions;}
8.ä»»å¡é¶æ®µ6
é¶æ®µ6ä»»å¡ï¼å¨MyConfigurationä¸è¯»åxxMapper.xmlï¼è½å¤å建MapperBean对象
ï¼1ï¼ä¿®æ¹ MyConfiguration.javaï¼æ·»å readMapper() æ¹æ³
/** * 读åxxMapper.xmlï¼å建MapperBean对象 * @param path xmlçè·¯å¾+æ件åï¼ä»ç±»çå 载路å¾å¼å§è®¡ç®ï¼è¥xmlæ件æ¾å¨resourceç®å½ä¸ï¼ç´æ¥ä¼ å
¥æ件åå³å¯ * @return è¿åMapperBean对象 */public MapperBean readMapper(String path) { MapperBean mapperBean = new MapperBean(); try { //è·åå°mapper.xmlæ件对åºçInputStream InputStream stream = loader.getResourceAsStream(path); SAXReader reader = new SAXReader(); //è·åå°xmlæ件对åºçdocument Document document = reader.read(stream); //å¾å°xmlçæ ¹èç¹ Element root = document.getRootElement(); //è·åå° namespace String namespace = root.attributeValue("namespace").trim(); //设置mapperBeançå±æ§interfaceName mapperBean.setInterfaceName(namespace); //éåè·årootçåèç¹-çæ Function Iterator rootIterator = root.elementIterator(); //ä¿åæ¥å£ä¸çæææ¹æ³ä¿¡æ¯ List<Function> list = new ArrayList<>(); while (rootIterator.hasNext()) { //ååºä¸ä¸ªåå
ç´ /** * <select id="getMonsterById" resultType="com.li.entity.Monster"> * select * from monster where id = ? * </select> */ Element e = (Element) rootIterator.next(); Function function = new Function(); String sqlType = e.getName().trim(); String funcName = e.attributeValue("id").trim(); //è¿éçresultTypeæ¯è¿åç±»åçå
¨è·¯å¾-å
¨ç±»å String resultType = e.attributeValue("resultType").trim(); String sql = e.getText().trim(); //å°ä¿¡æ¯å°è£
å° functionå¯¹è±¡ä¸ function.setSql(sql); function.setFuncName(funcName); function.setSqlType(sqlType); //è¿éçfunction.resultTypeåºè¯¥ä¸ºObjectç±»å //å æ¤ä½¿ç¨åå°çæ对象ï¼åæ¾å
¥functionä¸ Object instance = Class.forName(resultType).newInstance(); function.setResultType(instance); //å°å°è£
好çfunction对象æ¾å°listä¸ list.add(function); } mapperBean.setFunctions(list); } catch (Exception e) { e.printStackTrace(); } return mapperBean;}
ï¼2ï¼æµè¯
@Testpublic void readMapper() { MyConfiguration myConfiguration = new MyConfiguration(); MapperBean mapperBean = myConfiguration.readMapper("MonsterMapper.xml"); System.out.println("mapperBean=" + mapperBean);}
æµè¯ç»æï¼
mapperBean=MapperBean(interfaceName=com.li.mapper.MonsterMapper, functions=[Function(sqlType=select, funcName=getMonsterById, sql=select * from monster where id = ?, resultType=Monster(id=null, age=null, name=null, email=null, birthday=null, salary=0.0, gender=null), parameterType=null)])
9.ä»»å¡é¶æ®µ7
é¶æ®µ7ä»»å¡ï¼å®ç°å¨æ代çMapperçæ¹æ³-å¨æ代ççæMapper对象ï¼è°ç¨MyExecutoræ¹æ³
ï¼1ï¼MyMapperProxy.java
package com.li.limybatis.sqlsession; import com.li.limybatis.config.Function;import com.li.limybatis.config.MapperBean; import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.util.List; /** * @author æ * @version 1.0 * MyMapperProxyï¼å¨æ代ççæ Mapper对象ï¼è°ç¨ MyExecutoræ¹æ³ */public class MyMapperProxy implements InvocationHandler { private MySqlSession mySqlSession; private String mapperFile; private MyConfiguration myConfiguration; //æé å¨ public MyMapperProxy(MySqlSession mySqlSession, MyConfiguration myConfiguration, Class clazz) { this.mySqlSession = mySqlSession; this.myConfiguration = myConfiguration; this.mapperFile = clazz.getSimpleName() + ".xml"; } //å½æ§è¡Mapperæ¥å£ç代ç对象æ¹æ³æ¶ï¼ä¼æ§è¡å°invokeæ¹æ³ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MapperBean mapperBean = myConfiguration.readMapper(this.mapperFile); //å¤ææ¯å¦æ¯xmlæ件对åºçæ¥å£ if (!method.getDeclaringClass().getName().equals(mapperBean.getInterfaceName())) { //éè¿methodæ¿å°æ§è¡çæ¹æ³æå¨çæ¥å£çå称ï¼ä¸MapperBeanåæ¾çæ¥å£åæ¯è¾ return null; } //ååºMapperBeançfunctions List<Function> functions = mapperBean.getFunctions(); //å¤æå½åmapperBean解æ对åºçXMLæ件åï¼ææ¹æ³ if (null != functions && 0 != functions.size()) { for (Function function : functions) { //å¦æå½åè¦æ§è¡çæ¹æ³åfunction.getFuncName()ä¸æ · //说ææ们å¯ä»¥ä»å½åéåçfunction对象ä¸ï¼ååºç¸åºçä¿¡æ¯sqlï¼å¹¶æ§è¡æ¹æ³ if (method.getName().equals(function.getFuncName())) { //å¦æå½åfunctionè¦æ§è¡çSqlTypeæ¯selectï¼å°±å»æ§è¡selectOne /* * 说æï¼ * 1.å¦æè¦æ§è¡çæ¹æ³æ¯selectï¼å°±å¯¹åºæ§è¡selectOne * å 为æ们å¨MySqlSessionåªåäºä¸ä¸ªæ¹æ³ï¼selectOneï¼ * 2.å®é
ä¸åççMySqlSessionä¸åºè¯¥æå¾å¤çæ¹æ³ï¼åªæ¯è¿éç®åäº, * å®é
ä¸åºè¯¥æ ¹æ®ä¸åçå¹é
æ
åµè°ç¨ä¸åçæ¹æ³ï¼å¹¶ä¸è¿éè¦è¿è¡åæ°è§£æå¤çï¼ * è¿ææ¯è¾å¤æçå符串å¤çï¼æ¼æ¥sqlï¼å¤çè¿åç±»åçå·¥ä½ * 3.å 为è¿é主è¦æ³å®ç°mybatisçæmapperå¨æ代ç对象ï¼è°ç¨æ¹æ³çæºå¶ï¼æ以ç®å */ if ("select".equalsIgnoreCase(function.getSqlType())) { return mySqlSession .selectOne(function.getSql(), String.valueOf(args[0])); } } } } return null; }}
ï¼2ï¼ä¿®æ¹MySqlSession.javaï¼æ·»å æ¹æ³ï¼è¿åå¨æ代ç对象
/** * 1.å mapperçå¨æ代ç对象 * 2.è¿éç clazzå°æ¶ä¼ å
¥ç类似 MonsterMapper.class * 3.è¿åçå°±æ¯ MonsterMapper æ¥å£ç代ç对象 * 4.å½æ§è¡æ¥å£æ¹æ³æ¶ï¼éè¿ä»£ç对象è°ç¨ï¼ï¼ * æ ¹æ®å¨æ代çæºå¶ä¼æ§è¡å°MyMapperProxyçinvoke()æ¹æ³ * @param clazz * @param <T> * @return */public <T> T getMapper(Class<T> clazz) { //è¿åå¨æ代ç对象 return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new MyMapperProxy(this, myConfiguration, clazz));}
ï¼3ï¼å建 MySessionFactory.java
package com.li.limybatis.sqlsession; /** * @author æ * @version 1.0 * MySessionFactory-ä¼è¯å·¥å-è¿åä¼è¯SqlSession */public class MySessionFactory { public static MySqlSession openSession() { return new MySqlSession(); }}
ï¼4ï¼æµè¯
@Testpublic void openSession() { MySqlSession mySqlSession = MySessionFactory.openSession(); MonsterMapper mapper = mySqlSession.getMapper(MonsterMapper.class); System.out.println("mapperçè¿è¡ç±»å=" + mapper.getClass()); Monster monster = mapper.getMonsterById(1); System.out.println("monster--" + monster);}