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,它将包含: