主要包含mybatis-config.xml里面的配置文件解析、Mybatis的内置别名、dao层接口扫描的配置方式。
一、mybatis-config.xml配置解析
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://192.168.112.2:3306/javacode2018_2?characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </properties> <!-- environments:环境配置,可以配多个环境,default设置默认的环境id--> <environments default="development"> <!--environment:环境配置,id是环境的唯一标识--> <environment id="development"> <!--transactionManager:事务工厂配置,type配置的是org.apache.ibatis.transaction.TransactionFactory的实现类 默认的实现类有:org.apache.ibatis.transaction.managed.ManagedTransactionFactory org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory 跟spring整合的实现类有: org.mybatis.spring.transaction.SpringManagedTransactionFactory 这里的JDBC是mybatis的内置别名 --> <transactionManager type="JDBC"/> <!--dataSource:数据源配置 type配置的是org.apache.ibatis.datasource.DataSourceFactory的实现类 默认的实现类有:org.apache.ibatis.datasource.jndi.JndiDataSourceFactory org.apache.ibatis.datasource.pooled.PooledDataSourceFactory org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory 这里配置的POOLED是org.apache.ibatis.datasource.pooled.PooledDataSourceFactory的mybatis内置别名 --> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!--mappers mapper:配置的是具体的xml文件的路径,每个xml文件需要配置一个mapper标签 package:将多个xml文件存放在包内,统一配置。 --> <mappers> <!--此处用的是引用到具体xml文件的方式--> <!--<mapper resource="dao/UserDao.xml"/>--> <package name="dao"/> </mappers> </configuration>
二、dao层XML文件
namespace名称空间,用来配置关联的dao层接口。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="dao.UserDao"> </mapper>
三、XML文件中别名的使用
mybatis的XML文件中的paramaterType和resultType需要填写完整的类名,使用完整类型的时候可以点击该类名看能否进行跳转来检测类名是否填写正确。使用别名虽然能够缩短拼写,但是无法进行校验跳转,别名是不区分大小写的。如下是别名的实现方式:
1、使用typeAlias
type:完整的类名路径, alias:别名名称
<typeAlias type="entity.TUser" alias="user"></typeAlias>
案例:根据上文的配置调整,XML文件的SQL语句。
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultType="user"> select <include refid="Base_Column_List" /> from t_user where id = #{id,jdbcType=BIGINT} </select>
执行sqlSession进行调用,可以正常返回。
SqlSession sqlSession = sqlSessionFactory.openSession(true); TUserDao userDao = sqlSession.getMapper(TUserDao.class); TUser tUser = userDao.selectByPrimaryKey(1L); log.info("数据库查询结果为:{}", tUser); sqlSession.close();
2、使用package,进行批量的别名配置,使用package是会根据实体类的类型,默认生成一个别名。别名为类名的小写。
<typeAliases> <package name="entity"></package> </typeAliases>
案例:在mybatis-config.xml中添加完成别名的扫描包之后,更改XML的SQL语句。从下面的代码可以看出resultType是tuser,它的实际类名是TUser,是类名的小写。
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultType="tuser"> select <include refid="Base_Column_List" /> from t_user where id = #{id,jdbcType=BIGINT} </select>
使用sqlSession调用,可以正常返回。
Package扫描包下面的实体类,并根据实体类的名称生成别名,若包下面还包含子包,并且子包内有重名的实体类。则会报错。如下案例进行实现:
通过sqlSession调用xml文件的sql会报错,提示别名已经被使用。
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration.
Cause: org.apache.ibatis.type.TypeException: The alias 'TUser' is already mapped to the value 'entity.test.TUser'.
4、Mybatis的内置别名的配置:体现在TypeAliasRegistry和Configuration这两个类中。
org.apache.ibatis.type.TypeAliasRegistry的类中定义了Mybatis常用的内置别名。
public TypeAliasRegistry() { this.registerAlias("string", String.class); this.registerAlias("byte", Byte.class); this.registerAlias("long", Long.class); this.registerAlias("short", Short.class); this.registerAlias("int", Integer.class); this.registerAlias("integer", Integer.class); this.registerAlias("double", Double.class); this.registerAlias("float", Float.class); this.registerAlias("boolean", Boolean.class); this.registerAlias("byte[]", Byte[].class); this.registerAlias("long[]", Long[].class); this.registerAlias("short[]", Short[].class); this.registerAlias("int[]", Integer[].class); this.registerAlias("integer[]", Integer[].class); this.registerAlias("double[]", Double[].class); this.registerAlias("float[]", Float[].class); this.registerAlias("boolean[]", Boolean[].class); this.registerAlias("_byte", Byte.TYPE); this.registerAlias("_long", Long.TYPE); this.registerAlias("_short", Short.TYPE); this.registerAlias("_int", Integer.TYPE); this.registerAlias("_integer", Integer.TYPE); this.registerAlias("_double", Double.TYPE); this.registerAlias("_float", Float.TYPE); this.registerAlias("_boolean", Boolean.TYPE); this.registerAlias("_byte[]", byte[].class); this.registerAlias("_long[]", long[].class); this.registerAlias("_short[]", short[].class); this.registerAlias("_int[]", int[].class); this.registerAlias("_integer[]", int[].class); this.registerAlias("_double[]", double[].class); this.registerAlias("_float[]", float[].class); this.registerAlias("_boolean[]", boolean[].class); this.registerAlias("date", Date.class); this.registerAlias("decimal", BigDecimal.class); this.registerAlias("bigdecimal", BigDecimal.class); this.registerAlias("biginteger", BigInteger.class); this.registerAlias("object", Object.class); this.registerAlias("date[]", Date[].class); this.registerAlias("decimal[]", BigDecimal[].class); this.registerAlias("bigdecimal[]", BigDecimal[].class); this.registerAlias("biginteger[]", BigInteger[].class); this.registerAlias("object[]", Object[].class); this.registerAlias("map", Map.class); this.registerAlias("hashmap", HashMap.class); this.registerAlias("list", List.class); this.registerAlias("arraylist", ArrayList.class); this.registerAlias("collection", Collection.class); this.registerAlias("iterator", Iterator.class); this.registerAlias("ResultSet", ResultSet.class); }
对于mybatis-config.xml文件中使用的别名则体现在org.apache.ibatis.session.Configuration中。
public Configuration() { this.safeResultHandlerEnabled = true; this.multipleResultSetsEnabled = true; this.useColumnLabel = true; this.cacheEnabled = true; this.useActualParamName = true; this.localCacheScope = LocalCacheScope.SESSION; this.jdbcTypeForNull = JdbcType.OTHER; this.lazyLoadTriggerMethods = new HashSet(Arrays.asList("equals", "clone", "hashCode", "toString")); this.defaultExecutorType = ExecutorType.SIMPLE; this.autoMappingBehavior = AutoMappingBehavior.PARTIAL; this.autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE; this.variables = new Properties(); this.reflectorFactory = new DefaultReflectorFactory(); this.objectFactory = new DefaultObjectFactory(); this.objectWrapperFactory = new DefaultObjectWrapperFactory(); this.lazyLoadingEnabled = false; this.proxyFactory = new JavassistProxyFactory(); this.mapperRegistry = new MapperRegistry(this); this.interceptorChain = new InterceptorChain(); this.typeHandlerRegistry = new TypeHandlerRegistry(this); this.typeAliasRegistry = new TypeAliasRegistry(); this.languageRegistry = new LanguageDriverRegistry(); this.mappedStatements = (new Configuration.StrictMap("Mapped Statements collection")).conflictMessageProducer((savedValue, targetValue) -> { return ". please check " + savedValue.getResource() + " and " + targetValue.getResource(); }); this.caches = new Configuration.StrictMap("Caches collection"); this.resultMaps = new Configuration.StrictMap("Result Maps collection"); this.parameterMaps = new Configuration.StrictMap("Parameter Maps collection"); this.keyGenerators = new Configuration.StrictMap("Key Generators collection"); this.loadedResources = new HashSet(); this.sqlFragments = new Configuration.StrictMap("XML fragments parsed from previous mappers"); this.incompleteStatements = new LinkedList(); this.incompleteCacheRefs = new LinkedList(); this.incompleteResultMaps = new LinkedList(); this.incompleteMethods = new LinkedList(); this.cacheRefMap = new HashMap(); this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class); this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class); this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class); this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class); this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class); this.typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class); this.typeAliasRegistry.registerAlias("FIFO", FifoCache.class); this.typeAliasRegistry.registerAlias("LRU", LruCache.class); this.typeAliasRegistry.registerAlias("SOFT", SoftCache.class); this.typeAliasRegistry.registerAlias("WEAK", WeakCache.class); this.typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class); this.typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class); this.typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class); this.typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class); this.typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class); this.typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class); this.typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class); this.typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class); this.typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class); this.typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class); this.typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class); this.typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class); this.languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class); this.languageRegistry.register(RawLanguageDriver.class); }
通过查看,上面的代码,我们可以将mybatis-config.xml中的事务管理和数据库连接池的配置简写为JDBC和POOLED。
<!--transactionManager:事务工厂配置,type配置的是org.apache.ibatis.transaction.TransactionFactory的实现类 默认的实现类有:org.apache.ibatis.transaction.managed.ManagedTransactionFactory org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory 跟spring整合的实现类有: org.mybatis.spring.transaction.SpringManagedTransactionFactory 这里的JDBC是mybatis的内置别名 --> <transactionManager type="JDBC"/> <!--dataSource:数据源配置 type配置的是org.apache.ibatis.datasource.DataSourceFactory的实现类 默认的实现类有:org.apache.ibatis.datasource.jndi.JndiDataSourceFactory org.apache.ibatis.datasource.pooled.PooledDataSourceFactory org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory 这里配置的POOLED是org.apache.ibatis.datasource.pooled.PooledDataSourceFactory的mybatis内置别名 --> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
Mybatis类名的解析过程。优先从别名里面获取,然后在用classForName来获取class对象。
public <T> Class<T> resolveAlias(String string) { try { if (string == null) { return null; } else { String key = string.toLowerCase(Locale.ENGLISH); Class value; if (this.typeAliases.containsKey(key)) { value = (Class)this.typeAliases.get(key); } else { value = Resources.classForName(string); } return value; } } catch (ClassNotFoundException var4) { throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + var4, var4); } }
四、Mybatis属性配置的方式
1、通过通过properties元素来定义属性信息。
<properties> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/code2020_3?characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </properties>
<dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/>
</dataSource>
2、通过引入resources文件中的properties文件来定义属性信息。
在resources中添加properties的配置文件。
引入配置:
<!-- 引入外部配置文件 --> <properties resource="mybatis-config.properties"/>
3、还有一种方式是通过url引入远程的properties文件。很少使用。
<properties url="远程配置文件的路径" />
Mybatis对配置属性的解析。在org.apache.ibatis.builder.xml.XMLConfigBuilder#propertiesElement的方法上。从源码中可以看出同时引入了resource和url时会报错,resource和url的配置最终会覆盖掉XML文件里面的property标签设置的属性值。一般我们用resource引入。若是最终在代码中有对Properties属性进行设置,则最终以代码设置的属性值为准。
private void propertiesElement(XNode context) throws Exception { if (context != null) { Properties defaults = context.getChildrenAsProperties(); String resource = context.getStringAttribute("resource"); String url = context.getStringAttribute("url"); if (resource != null && url != null) { throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other."); } if (resource != null) { defaults.putAll(Resources.getResourceAsProperties(resource)); } else if (url != null) { defaults.putAll(Resources.getUrlAsProperties(url)); } Properties vars = this.configuration.getVariables(); if (vars != null) { defaults.putAll(vars); } this.parser.setVariables(defaults); this.configuration.setVariables(defaults); } }
五、Mybatis中mappers的配置方式
1、使用mapper + class属性的配置,多个dao层接口,需要配置多个标签,配置比较麻烦,不推荐使用。
<mappers>
<mapper class="接口的完整类名" />
</mappers>
2、使用mapper + package属性配置。直接扫描package包下的所有接口。这种方式会扫描该包路径下的所有接口,并对其进行注册。而且使用的时候需要dao层接口和XML文件同时放在这个包下(可以在这个报下创建子包用来存放XML文件)。
<mappers>
<package name="dao"/>
</mappers>
3、使用mapper + resource属性配置。多个XML文件需要写多个mapper标签,个人觉得用package会比较便捷一些。
<mappers> <mapper resource="mapper/TUserDao.xml"/> </mappers>