mybatis源碼
❶ 什麼是mybatis框架
MyBatis 本是apache的一個開源項目iBatis, 是一個優秀的持久層框架。它對jdbc的操作資料庫的過程進行封裝,使開發者只需要關注 sql 本身,而不需要花費精力去處理例如注冊驅動、創建connection、創建statement、手動設置參數、結果集檢索等jdbc繁雜的過程代碼。Mybatis通過xml或註解的方式將要執行的各種statement(statement、preparedStatemnt)配置起來,並通過java對象和statement中的sql進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射成java對象並返回。
❷ spring springmvc mybatis整合 怎麼實現許可權登錄 源代碼
給你個思路,你去實現HandlerIntercepter這個介面去實現判斷當前用戶是否登錄
如果當前用戶沒有登錄,則將提示用戶登錄,反之。
❸ 求網上購物商城源代碼。java,springboot,mybatis,MySQLthymeleaf
你應該去csdn或者github找,有免費的源碼
❹ mybatis源碼如何下載
https://github.com/mybatis/mybatis-3/releases
下面有源碼下載,源碼是個zip壓縮文件
❺ 初看Mybatis 源碼 SQL是怎麼執行的
一條sql語句到底是怎麼執行的?我們知道Mybatis其實是對JDBC的一個封裝。假如我執行
session.update("com.mybatis..AuthUserDao.updateAuthUserEmailByName", [email protected]);
語句,追蹤下來,Executor、 BaseStatementHandler等等。在 SimpleExecutor 中有如下代碼:
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
1. 首先獲取相關配置信息,這個在初始化時,從配置文件中解析而來
2. 新建了一個handler
3. 做了執行statement之前的准備工作。看看準備了些什麼,跟蹤代碼,最後進入了DataSource類的doGetConnection方法,該方法做如下操作:
private Connection doGetConnection(Properties properties) throws SQLException {
initializeDriver();
Connection connection = DriverManager.getConnection(url, properties);
configureConnection(connection);
return connection;
}
private synchronized void initializeDriver() throws SQLException {
if (!registeredDrivers.containsKey(driver)) {
Class<?> driverType;
try {
if (driverClassLoader != null) {
driverType = Class.forName(driver, true, driverClassLoader);
} else {
driverType = Resources.classForName(driver);
}
// DriverManager requires the driver to be loaded via the system ClassLoader.
// http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
Driver driverInstance = (Driver)driverType.newInstance();
DriverManager.registerDriver(new DriverProxy(driverInstance));
registeredDrivers.put(driver, driverInstance);
} catch (Exception e) {
throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
}
}
}
原來是通過prepareStatement 來執行了 我們初始化jdbc的操作。Class.forName DriverManager.getConnection. 這兩步是在這裡面完成的。
4. 將執行sql的部分交給handler
繼續跟蹤handler 可以看到SimpleStatementHandler 中。如下執行這個update語句
public int update(Statement statement)
throws SQLException {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
if (keyGenerator instanceof Jdbc3KeyGenerator) {
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
statement.execute(sql);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}
這邊就完成了statement的操作,整個過程就是我們Jdbc的過程。原來真的就是對JDBC的簡單封裝。
其實Mybatis的整個執行過程,理解起來分為如下幾個過程:
1. 載入配置文件
2. 解析配置文件,從配置文件中解析出來 datasource、mapper文件、事務配置等等。將配置信息保存在對象內
3. 調用相關語句,執行sql。在執行的方法中分別完成JDBC的一系列操作。
❻ 怎麼沒有mybatis源碼解析相關的文檔
我們還記得是這樣配置sqlSessionFactory的:
[java] view plain
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:configuration.xml"></property>
<property name="mapperLocations" value="classpath:com/xxx/mybatis/mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.tiantian.mybatis.model" />
</bean>
這里配置了一個mapperLocations屬性,它是一個表達式,sqlSessionFactory會根據這個表達式讀取包com.xxx.myts.mapper下面的所有xml格式文件,那麼具體是怎麼根據這個屬性來讀取配置文件的呢?
答案就在SqlSessionFactoryBean類中的buildSqlSessionFactory方法中:
[java] view plain
if (!isEmpty(this.mapperLocations)) {
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
if (logger.isDebugEnabled()) {
logger.debug("Parsed mapper file: '" + mapperLocation + "'");
}
}
}
mybatis使用XMLMapperBuilder類的實例來解析mapper配置文件。
[java] view plain
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration, resource, sqlFragments);
}
[java] view plain
private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
super(configuration);
this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
this.parser = parser;
this.sqlFragments = sqlFragments;
this.resource = resource;
}
接著系統調用xmlMapperBuilder的parse方法解析mapper。
[java] view plain
public void parse() {
//如果configuration對象還沒載入xml配置文件(避免重復載入,實際上是確認是否解析了mapper節點的屬性及內容,
//為解析它的子節點如cache、sql、select、resultMap、parameterMap等做准備),
//則從輸入流中解析mapper節點,然後再將resource的狀態置為已載入
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
//解析在configurationElement函數中處理resultMap時其extends屬性指向的父對象還沒被處理的<resultMap>節點
parsePendingResultMaps();
//解析在configurationElement函數中處理cache-ref時其指向的對象不存在的<cache>節點(如果cache-ref先於其指向的cache節點載入就會出現這種情況)
parsePendingChacheRefs();
//同上,如果cache沒載入的話處理statement時也會拋出異常
parsePendingStatements();
}
mybatis解析mapper的xml文件的過程已經很明顯了,接下來我們看看它是怎麼解析mapper的:
[java] view plain
private void configurationElement(XNode context) {
try {
//獲取mapper節點的namespace屬性
String namespace = context.getStringAttribute("namespace");
if (namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
//設置當前namespace
builderAssistant.setCurrentNamespace(namespace);
//解析mapper的<cache-ref>節點
cacheRefElement(context.evalNode("cache-ref"));
//解析mapper的<cache>節點
cacheElement(context.evalNode("cache"));
//解析mapper的<parameterMap>節點
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//解析mapper的<resultMap>節點
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析mapper的<sql>節點
sqlElement(context.evalNodes("/mapper/sql"));
//使用XMLStatementBuilder的對象解析mapper的<select>、<insert>、<update>、<delete>節點,
//myts會使用MappedStatement.Builder類build一個MappedStatement對象,
//所以myts中一個sql對應一個MappedStatement
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
configurationElement函數幾乎解析了mapper節點下所有子節點,至此myts解析了mapper中的所有節點,並將其加入到了Configuration對象中提供給sqlSessionFactory對象隨時使用。這里我們需要補充講一下myts是怎麼使用XMLStatementBuilder類的對象的parseStatementNode函數借用MapperBuilderAssistant類對象builderAssistant的addMappedStatement解析MappedStatement並將其關聯到Configuration類對象的:
[java] view plain
public void parseStatementNode() {
//ID屬性
String id = context.getStringAttribute("id");
//databaseId屬性
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
//fetchSize屬性
Integer fetchSize = context.getIntAttribute("fetchSize");
//timeout屬性
Integer timeout = context.getIntAttribute("timeout");
//parameterMap屬性
String parameterMap = context.getStringAttribute("parameterMap");
//parameterType屬性
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
//resultMap屬性
String resultMap = context.getStringAttribute("resultMap");
//resultType屬性
String resultType = context.getStringAttribute("resultType");
//lang屬性
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
Class<?> resultTypeClass = resolveClass(resultType);
//resultSetType屬性
String resultSetType = context.getStringAttribute("resultSetType");
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
String nodeName = context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
//是否是<select>節點
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
//flushCache屬性
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
//useCache屬性
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
//resultOrdered屬性
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
// Include Fragments before parsing
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
// Parse selectKey after includes and remove them.
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
//resultSets屬性
String resultSets = context.getStringAttribute("resultSets");
//keyProperty屬性
String keyProperty = context.getStringAttribute("keyProperty");
//keyColumn屬性
String keyColumn = context.getStringAttribute("keyColumn");
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
//useGeneratedKeys屬性
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? new Jdbc3KeyGenerator() : new NoKeyGenerator();
}
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
由以上代碼可以看出myts使用XPath解析mapper的配置文件後將其中的resultMap、parameterMap、cache、statement等節點使用關聯的builder創建並將得到的對象關聯到configuration對象中,而這個configuration對象可以從sqlSession中獲取的,這就解釋了我們在使用sqlSession對資料庫進行操作時myts怎麼獲取到mapper並執行其中的sql語句的問題。
❼ mybatis工作原理及為什麼要用
一、mybatis的工作原理:
MyBatis 是支持普通 SQL查詢,存儲過程和高級映射的優秀持久層框架。MyBatis 消除了幾乎所有的JDBC代碼和參數的手工設置以及結果集的檢索。
MyBatis使用簡單的 XML或註解用於配置和原始映射,將介面和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java對象)映射成資料庫中的記錄。
每個MyBatis應用程序主要都是使用SqlSessionFactory實例的,一個SqlSessionFactory實例可以通過SqlSessionFactoryBuilder獲得。用xml文件構建SqlSessionFactory實例是非常簡單的事情。
推薦在這個配置中使用類路徑資源,但可以使用任何Reader實例,包括用文件路徑或file://開頭的url創建的實例。MyBatis有一個實用類----Resources,它有很多方法,可以方便地從類路徑及其它位置載入資源。
二、使用mybatis的原因:因為mybatis具有許多的優點,具體如下:
1、簡單易學:本身就很小且簡單。沒有任何第三方依賴,最簡單安裝只要兩個jar文件+配置幾個sql映射文件易於學習,易於使用,通過文檔和源代碼,可以比較完全的掌握它的設計思路和實現。
2、靈活:mybatis不會對應用程序或者資料庫的現有設計強加任何影響。 sql寫在xml里,便於統一管理和優化。通過sql語句可以滿足操作資料庫的所有需求。
3、解除sql與程序代碼的耦合:通過提供DAO層,將業務邏輯和數據訪問邏輯分離,使系統的設計更清晰,更易維護,更易單元測試。sql和代碼的分離,提高了可維護性。
4、提供映射標簽,支持對象與資料庫的orm欄位關系映射。
5、提供對象關系映射標簽,支持對象關系組建維護。
6、提供xml標簽,支持編寫動態sql。
(7)mybatis源碼擴展閱讀:
mybatis的功能構架:
1、API介面層:提供給外部使用的介面API,開發人員通過這些本地API來操縱資料庫。介面層一接收到調用請求就會調用數據處理層來完成具體的數據處理。
2、數據處理層:負責具體的SQL查找、SQL解析、SQL執行和執行結果映射處理等。它主要的目的是根據調用的請求完成一次資料庫操作。
3、基礎支撐層:負責最基礎的功能支撐,包括連接管理、事務管理、配置載入和緩存處理,這些都是共用的東西,將他們抽取出來作為最基礎的組件。為上層的數據處理層提供最基礎的支撐。
❽ 請問誰有使用spring+mybatis+springMVC+oracle開發的系統啊,能不能分享一下源碼啊
這個實現起來代碼是稍有點長 建議自己搜索一下 或是系統的學習一下
❾ 什麼是mybatis
MyBatis 是一個可以自定義SQL、存儲過程和高級映射的持久層框架。MyBatis 摒除了大部分的JDBC代碼、手工設置參數和結果集重獲。MyBatis 只使用簡單的XML 和註解來配置和映射基本數據類型、Map 介面和POJO 到資料庫記錄。相對Hibernate和Apache OJB等「一站式」ORM解決方案而言,Mybatis 是一種「半自動化」的ORM實現。
需要使用的Jar包:mybatis-3.0.2.jar(mybatis核心包)。mybatis-spring-1.0.0.jar(與Spring結合包)。
MyBatis的前身是ibatis,但是在配置sql的語法上有明顯的區別,並且spring目前的版本封裝mybatis,至於mybatis-spring.jar文件也是mybatis團隊復雜開發的jar包,用於和spring整合。之前ibatis的源碼託管方是apache,而mybatis是google。
❿ 如何修改mybatis generator tinyint byte
首先說說上一篇最後提到的關於自定義注釋的問題,想實現這個功能就需要修改org.mybatis.generator.internal.DefaultCommentGenerator這個類。我將裡面一些主要的方法講下。
addJavaFileComment(CompilationUnit compilationUnit)
給Java文件加註釋,這個注釋是在文件的頂部,也就是package上面。
addComment(XmlElement xmlElement)
給生成的XML文件加註釋。大象將這個方法清空了,不生成注釋。
addClassComment(InnerClass innerClass,IntrospectedTable introspectedTable)
Java類的類注釋。
請注意紅線的getRemarks()方法,這個remarks屬性在原來的FullyQualifiedTable裡面是沒有的,這是大象自己加上去的,就是為了保存表的注釋信息。那是在哪裡加進去的呢?請看org.mybatis.generator.internal.db.DatabaseIntrospector這個類,大概瀏覽下就會發現,資料庫表以及列的信息讀取,類型設置都是由它來完成的,定位到608行,正好這里是個空行,插入幾行代碼。如下:
這樣我們就取到了表的注釋信息,看到這里應該就會明白了吧?
另外我需要說明的是,想通過databaseMetaData.getTables()來獲得表注釋的童鞋,這個做法是沒用的,大象已經試過了,這個結果集裡面的rs.getString("REMARKS")得到的是一個空字元串,什麼都木有。而且大象還想吐槽下,網上一大堆說返回的這個結果集是10列,呵呵,是的么?我debug了好久發現它還是只有5列,不知道這10列是從哪來的,請列印出10列的童鞋告之是怎麼做的,我用的mysql驅動是5.1.29
addFieldComment(Field field, IntrospectedTable introspectedTable,IntrospectedColumn introspectedColumn)
Java屬性注釋。注釋為空就不給屬性添加。
addGetterComment(Method method,IntrospectedTable introspectedTable,IntrospectedColumn introspectedColumn)
給getter方法加註釋。這里添加註釋的方法和Field一樣,大象把這個方法以及addSetterComment方法都清空了,因為我比較習慣把注釋加到屬性上面,如果你習慣在getter方法上面加註釋可以自行改一下。
上面這些修改做完後,記得要在org.mybatis.generator.codegen.mybatis3.model.BaseRecordGenerator的61行增加下面這行代碼:
commentGenerator.addClassComment(topLevelClass, introspectedTable);
因為mybatis-generator源碼中本來就是不加類注釋的。
大家都在不同的公司,要求肯定都不一樣,大象沒法滿足所有人,只對該類做了一定程度的修改,姑且把它當做一個示例模板吧,主要是弄明白怎麼改就成了。
mybatis-generator在1.3.2版里對生成xml的namespace作了修改,不再用表名當為namespace的值,而是用包結構+類名+Mapper後綴的形式設置,大象不喜歡這么復雜做法,所以這里需要改一改,只保留類名+Mapper的命名形式。去掉org.mybatis.generator.api.IntrospectedTable類的907行與908行代碼。
接下來再來說說對大對象類型的處理,mybatis-generator默認會把所有jdbcType為:BINARY、BLOB、CLOB、LONGVARBINARY、LONGVARCHAR、VARBINARY這些類型都作為大對象,反應出來的效果就是生成的pojo類會多一個類名+WithBLOBs.java的文件(含有的大對象個數大於1時),而在XML裡面也會增加一個id為ResultMapWithBLOBs的resultMap,它繼承BaseResultMap,大象一向喜歡簡單的風格,這看得太不爽了。如果你覺得無所謂,不需要修改,請跳過這段往下看。
表中的text或blob等類型,通過databaseMetaData.getColumns()取出來後,它的rs.getInt("DATA_TYPE")值是與java.sql.Types對應的。
text類型的值:Types.LONGVARCHAR
blob類型是值:Types.LONGVARBINARY
它用org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl解析java類型與jdbc類型,然後設置到org.mybatis.generator.api.IntrospectedColumn的jdbcTypeName屬性里,最關鍵的地方到了,IntrospectedColumn類第156行有個isBLOBColumn()方法,它就是用來判斷是否生成xxxWithBLOBs.java和ResultMapWithBLOBs的條件。當然mybatis-generator不會這么直接用,它在裡面定義了一個Rules介面,由它來統一進行調用。所以我們只需要把isBLOBColumn()裡面的代碼都去掉,直接返回false就可以了,再結合配置文件中的columnOverride屬性就能達到目的。
jdbcType指定的值就是生成xml後result裡面對應的類型,javaType與生成的pojo裡面屬性類型一致,這里其實可以不定義javaType,但是當資料庫的表欄位有的定義為tinyint時,如果不給它指定類型,那麼默認生成的java類型就是java.lang.Byte,假如你想轉換類型,而且保證不會超出欄位類型的大小限制,那麼你可以將它的javaType設為java.lang.Integer
經過這么一番修改之後,輸出結果已經比較理想了,但是xml文件看上去還是有點問題,元素與元素之間沒空行,看起來好別扭。恩,這里要給它加上空行,所以請找到org.mybatis.generator.api.dom.xml.XmlElement類的getFormattedContent方法,這個方法有個參數:indentLevel,通過名字我們可以很直觀的理解它的作用就是來控制縮進等級,它的初始值為0,這表示不縮進,當變成1時就是縮進一級,也即縮進四個空格,後面以此類推,我們應該還注意到,方法內部用到了遞歸,所以它是從最底元素開始,再一步步返回,所以我們就應該在indentLevel為1的元素後面加上換行。
在生成xml的文件裡面,我們看到有一個update元素,id為updateByPrimaryKey,這個基本上用不到,但是你還不能在table里加上enableUpdateByPrimaryKey="false",如果你這么做,雖然updateByPrimaryKey沒有了,但updateByPrimaryKeySelective也會消失。所以這時請看看org.mybatis.generator.codegen.mybatis3.xmlmapper.XMLMapperGenerator這個類,getSqlMapElement()裡面,有大量的addXXX方法,這些方法裡面每個都用到了Rules規則來處理是否執行,比如我們在table裡面加了enableDeleteByExample="false",它對應的是addDeleteByExampleElement(),而它又調用了introspectedTable.getRules().generateDeleteByExample()方法,再進入到generateDeleteByExample()裡面,我們可以看到紅線部分,上一篇大象講過,在載入配置文件的時候,TableConfiguration會將table中的這些屬性設置到對應的屬性里,所以說其實最後還是回到了判斷enableDeleteByExample的布爾值上面。
上面啰嗦了一大堆,現在再來解決之前提到的問題,如何去掉id為updateByPrimaryKey的update元素,注釋掉()或直接去掉這行代碼,跟蹤代碼你會發現,它和()的rules驗證裡面都用到了enableUpdateByPrimaryKey的值。或者你不想採取我說的這個辦法,而是改BaseRules的(),讓它直接返回false
最後大象再嘮叨一句,這些addXXX方法的順序決定了生成xml文件中的元素順序,所以有代碼潔癖的人可以作下調整。
上一篇加這一篇都是講怎麼少量的改動源碼以實現自定義文件輸出,寫的比較凌亂,不是很系統,完全是從實用的角度出發,關鍵還是大象水平有限,有什麼錯誤還請大家幫我指出來,謝謝!
改了這么多,總要看下效果吧,下一篇大象將寫個測試看看生成的結果,然後用maven assembly將它打包生成一個zip,它將包含: