动态 SQL
如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
- 动态 SQL 是 MyBatis 强大特性之一。极大的简化我们拼装 SQL 的操作。
- 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。
- MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。
if、where
<!-- List<Teacher> getTeacherByConditions(Teacher teacher); -->
<select id="getTeacherByConditions" resultMap="teacherMap">
SELECT * FROM teacher
<!-- <where>可以删除前面多余的 AND:SQL 查询条件的 AND 一定要写前面 -->
<!-- <bind> 可以将 OGNL 表达式的值绑定到一个变量中,方便后来引用这个变量的值(没用) -->
<bind name="_tname" value="'%'+tname+'%'">
<where>
<!-- ↓ 判断条件,取出传入的JavaBean的属性,判断其是否为空 -->
<if test="tname!=null">
AND id > #{_tname}
</if>
<if test="subject!=null && !subject.equals("")">
AND subject LIKE #{subject}
</if>
<if test="birthday!=null">
AND birth_date < #{birthday}
</if>
</where>
</select>
trim、sql (include)
<!-- 抽取可重用 SQL -->
<sql id="selectTeacher">SELECT * FROM teacher</sql>
<!-- List<Teacher> getTeacherByConditions(Teacher teacher); -->
<select id="getTeacherByConditions" resultMap="teacherMap">
<!--引用可重用 SQL-->
<include refid="selectTeacher"></include>
<!-- <trim> 自定义字符串截取规则
prefix: 添加一个前缀
suffix: 添加一个后缀
prefixOverrides: 如果字符串开头为指定值,则去除
suffixOverrides: 如果字符串尾部为指定值,则去除
-->
<trim prefix="WHERE" suffixOverrides="AND">
<if test="tid!=null">
id > #{tid} AND
</if>
<if test="subject!=null && !subject.equals("")">
subject LIKE #{subject} AND
</if>
<if test="birthday!=null">
birth_date < #{birthday} AND
</if>
</trim>
</select>
choose (when, otherwise)
<!-- List<Teacher> getTeacherByOneCondition(Teacher teacher) -->
<select id="getTeacherByOneCondition" resultMap="teacherMap">
SELECT * FROM teacher
<where>
<choose>
<when test="tid!=null">
id > #{tid}
</when>
<when test="subject!=null && !subject.equals("")">
subject LIKE #{subject}
</when>
<when test="birthday!=null">
birth_date < #{birthday}
</when>
<otherwise>1=1</otherwise>
</choose>
</where>
</select>
set
<!--
// 带哪些字段,更新哪些字段 → 致使 @ModelAttribute 无使用场景
public int updateTeacher(Teacher teacher);
-->
<update id="updateTeacher">
UPDATE teacher
<!-- UPDATE teacher SET <trim suffix="WHERE" suffixOverrides=","> -->
<!-- set 去除末尾多余的',' -->
<set>
<if test="tname!=null && !tname.equals("")">
tname=#{tname},
</if>
<if test="subject!=null && !subject.equals("")">
subject=#{subject},
</if>
<if test="address!=null && !address.equals("")">
address=#{address},
</if>
<if test="birthday!=null">
birth_date=#{birthday},
</if>
</set>
<where>
tid = #{tid}
</where>
</update>
foreach
动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。
<!-- List<Teacher> getTeacherByIdIn(List<Integer> ids) -->
<select id="getTeacherByIdIn" resultMap="teacherMap">
SELECT * FROM teacher WHERE tid IN
<!--
collection="" 要遍历的集合
遍历的是 List:
> index 保存当前索引
> item 将当前遍历出的元素赋值给指定的变量
遍历的是 Map:
> index 指定的变量就是保存当前遍历的 entry 的 key
> item 指定的变量保存当前遍历的 entry 的 value
·······················
separator="" 元素之间的分隔符
open="" 以什么开始
close="" 以什么结束
-->
<if test="ids.size > 0">
<foreach collection="list" separator="," index="" item="id" open="(" close=")">
#{id}
</foreach>
</if>
</select>
<!-- void addTeachers(@Param("teachers") List<Teacher> teachers) -->
<insert id="addTeachers">
INSERT INTO teacher(tname, subject) VALUES
<foreach collection="teachers" separator="," item="teacher">
(#{teacher.tname}, #{teacher.subject})
</foreach>
</insert>
<!--
MYSQL:
除了将 VALUES 后的语句循环执行外,还可以将整条 SQL 语句都放入循环体中,语句末尾用';'
除此之外,连接 DB 的 url 末尾还必须要增添一个连接属性:allowMultiQueries=true
Oracle: 多条插入 SQL 要放在 begin...end; 中
-->
OGNL
在 MyBatis 中,传入的参数可以用来做判断,额外的还有两个内置参数:
_parameter:
若传入了单个参数,就代表这个参数
若传入了多个参数,就代表这多个参数封装起来的Map
_databaseId: 如果配置了 databaseIdProvider,则该参数代表当前环境
<if test="_databaseId == 'mysql'"> ... </if>
<if test="_databaseId == 'oracle'"> ... </if>
缓存机制
缓存:暂时存储一些数据,可以极大的提升查询效率。MyBatis 系统中默认定义了两级缓存。
- 一级缓存:线程级别的缓存;基于 SqlSession 级别的,也称为本地缓存;默认开启
- 二级缓存:全局范围的缓存;基于 namespace 级别的缓存。除过当前线程的 SqlSession 能用外,其他也可以二级缓存。需要手动开启和配置
一级缓存
简述
- 一级缓存(local cache),即本地缓存,作用域默认为 SqlSession。当 Session flush 或 close 后,该 Session 中的所有 Cache 将被清空。
- 本地缓存不能被关闭,但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域。
- 在 Mybatis 3.1 之后,可以配置本地缓存的作用域(在 mybatis.xml 中配置)
演示
@Test
public void test() {
SqlSession sqlSession = sqlSessionFactory.openSession(true);
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher1 = mapper.getTeacherByTid(1);
System.out.println(teacher1);
Teacher teacher2 = mapper.getTeacherByTid(1);
System.out.println(teacher2);
System.out.println(teacher1 == teacher2); // true
}
同一次会话期间只要查询过的数据都会保存在当前 SqlSession 的一个 HashMap 中。
失效情况
每次查询,先看一级缓存(SqlSession 级别的缓存) 中有没有,如果没有再去发新的 SQL。
- 不同的 SqlSession,使用不同的一级缓存;只有在同一个 SqlSession 期间查询到的数据会保存在这个 SqlSession 的缓存中;下次这个 SqlSession 再去查询会先在它自己的缓存中去找。
- 同一条 SQL 语句,但是参数不同,就会导致 key 有变化,所以还会发新的 SQL
- 在这个 SqlSession 执行期间执行任何一次增删改操作,都会致使缓存被清空
- 同一个 SqlSession 两次查询期间手动清空了缓存
源码
public class PerpetualCache implements Cache {
private String id;
// 底层就是一个 Map
private Map<Object, Object> cache = new HashMap<Object, Object>();
public PerpetualCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public int getSize() {
return cache.size();
}
@Override
public void putObject(Object key, Object value) {
cache.put(key, value);
}
@Override
public Object getObject(Object key) {
return cache.get(key);
}
@Override
public Object removeObject(Object key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
@Override
public boolean equals(Object o) {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
if (this == o) {
return true;
}
if (!(o instanceof Cache)) {
return false;
}
Cache otherCache = (Cache) o;
return getId().equals(otherCache.getId());
}
@Override
public int hashCode() {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
return getId().hashCode();
}
}
BaseExecutor
@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter
, RowBounds rowBounds, ResultHandler resultHandler
, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource())
.activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
// 缓存中有没有
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) { // 有
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else { // 没有
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
二级缓存
简述
- 二级缓存(second level cache),全局作用域缓存
- MyBatis 提供二级缓存的接口以及实现,缓存实现要求 POJO 实现 Serializable 接口
- 二级缓存在 SqlSession 关闭或提交之后才会生效 → 这也就意味着不可能会出现一级缓存和二级缓存中有同一个数据!
- 二级缓存中:不关就会一直放在一级缓存;只有一级缓存关闭,数据才会被迁移至二级缓存
- 一级缓存中:二级缓存中没有此数据,就会看一级缓存,一级缓存中没有就会去查 DB。DB 的查询结果放在一级缓存中了
- 任何时候都是先看二级缓存,再看一级缓存
原理
二级缓存基于 namespace。没有配置 <cache>
的 Mapper.xml 就没有二级缓存。并且,在二级缓存中,不同 Mapper 的数据都是存放在各自的 Map 中。
缓存相关属性
- eviction="LRU" 缓存回收策略
- LRU – 最近最少使用的:移除最长时间不被使用的对象。
- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
- SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
- WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
- flushInterval 刷新间隔
- 单位毫秒
- 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
- size:引用数目
- 正整数
- 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
- readOnly:只读
- true:只读缓存;会给所有调用者返回缓存对象的引用。因此这些对象不能被修改。这提供了很重要的性能优势。
- false:读写缓存;会返回缓存对象的拷贝(通过反序列化)。这会慢一些,但是安全,因此默认是 false。
缓存有关设置
- 全局 setting 的 cacheEnable:配置二级缓存的开关
<setting name="cacheEnabled" value="true"/>
<select>
的 useCache 属性:配置这个 select 是否使用二级缓存 (一级缓存一直是使用的)- 增删改标签的 flushCache 属性:增删改默认
flushCache=true
,查询默认flushCache=false
。SQL 执行以后,会同时清空一级和二级缓存。 sqlSession.clearCache()
只是用来清除一级缓存- 当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
整合第三方缓存
- MyBatis 定义了 Cache 接口方便我们进行自定义扩展。
- EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider。
- EhCache 使用步骤
- 导入 ehcache 包,以及整合包,日志包
ehcache-core-2.6.8.jar (ehcache 核心包) mybatis-ehcache-1.0.3.jar (ehcache 整合包) slf4j-api-1.6.1.jar slf4j-log4j12-1.6.2.jar
- 编写 ehcache.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!-- 磁盘保存路径 --> <diskStore path="U:ehcache" /> <defaultCache maxElementsInMemory="3000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
- 在 Mapper.xml 中配置 cache 标签
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
- 导入 ehcache 包,以及整合包,日志包
- Tips
- POJO 可以不用实现 Serializable 接口
- 参照缓存:若想在命名空间中共享相同的缓存配置和实例。可用
<cache-ref>
来引用另外一个缓存。<cache-ref namespace="cn.edu.nuist.mapper.TeacherMapper" />
SSM 整合
导包
Spring
[AOP核心]
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
[IOC核心]
commons-logging-1.1.3.jar
spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
[JDBC核心]
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
SpringMVC
[Ajax]
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
[数据校验]
hibernate-validator-5.0.0.CR2.jar
hibernate-validator-annotation-processor-5.0.0.CR2.jar
classmate-0.8.0.jar
jboss-logging-3.1.1.GA.jar
validation-api-1.1.0.CR1.jar
[上传下载]
commons-fileupload-1.2.1.jar
commons-io-2.0.jar
[jstl]
jstl.jar
standard.jar
[SpringMVC核心]
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar
MyBatis
[MyBatis核心]
mybatis-3.4.1.jar
mybatis-spring-1.3.0.jar
[ehcache整合]
ehcache-core-2.6.8.jar
mybatis-ehcache-1.0.3.jar
log4j-1.2.17.jar
slf4j-api-1.7.21.jar
slf4j-log4j12-1.7.21.jar
database
mysql-connector-java-5.1.37-bin.jar
c3p0-0.9.1.2.jar
写配置
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- REST 过滤器 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置 spring 容器启动 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 配置 SpringMVC 前端控制器 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
SpringMVC 配置文件
applicationContext-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:component-scan base-package="cn.edu.nuist" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 文件上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="#{1024*1024*20}"></property>
</bean>
<!-- 扫静态 -->
<mvc:default-servlet-handler/>
<!-- 扫动态 -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
Spring 配置文件
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<!-- 1. 包扫描 -->
<context:component-scan base-package="cn.edu.nuist">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 2. 导入外部配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<!-- 3. 配数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
<property name="minPoolSize" value="${jdbc.minPoolSize}"></property>
</bean>
<!-- 4. 整合 MyBatis !!! -->
<!-- 4.1 根据配置文件,生产 SqlSessionFactory 的工厂 bean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定 MyBatis 全局配置文件的位置 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<!-- 引用 Spring 创建的数据源 (事务控制是 Spring 在做) -->
<property name="dataSource" ref="dataSource"></property>
<!-- 指定 Mapper 映射文件的位置 -->
<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>
</bean>
<!-- 4.2 会查找类路径下的 Mapper<I>[映射器],并自动将它们创建成 MapperFactoryBean -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 为映射器接口文件设置基本的包路径,每个映射器将会在指定的包路径中递归地被搜索到 -->
<property name="basePackage" value="cn.edu.nuist.mapper"></property>
</bean>
<!-- <mybatis-spring:scan base-package="cn.edu.nuist.mapper"> -->
<!-- 5. [事务控制] 配置事务管理器,让其控制数据源中连接的关闭和提交 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 6. 基于 XML 配置事务,详见 [Re:Spring-2]#7.6 -->
<aop:config>
<!-- 配置切入点表达式((哪些方法切入事务) -->
<aop:pointcut expression="execution(* cn.edu.nuist.service.*.*(..))" id="txPoint"/>
<aop:advisor advice-ref="myTx" pointcut-ref="txPoint"/>
</aop:config>
<!-- 7. 事务增强(属性)-->
<tx:advice id="myTx" transaction-manager="transactionManager">
<!-- 配置事务属性 -->
<tx:attributes>
<tx:method name="*" rollback-for="java.lang.Exception"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T>
- MapperFactoryBean 创建的代理类实现了
Mapper<I>
,并且注入到应用程序中。因为代理创建在运行时环境中(Runtime),那么指定的映射器必须是一个接口,而不是一个具体的实现类。 - 数据映射器
Mapper<I>
不需要显示写一个注解交给 Spring 管理,然后在 Service 层进行注入。因为Mapper<I>
其实是供 MapperFactoryBean 创建的代理类来实现的,然后自动放到 Spring 的 IOC 容器中,在 Service 实现中注入的是 MapperFactoryBean 创建的代理类。
https://www.cnblogs.com/Joe-Go/p/10256241.html
https://www.cnblogs.com/xiaolang8762400/p/7399274.html
mybatis 配置文件
<?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>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
</configuration>
其他配置文件
dbconfig.properties
jdbc.user=root
jdbc.password=root
jdbc.jdbcUrl=jdbc:mysql:///test
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.maxPoolSize=100
jdbc.minPoolSize=10
测试
略
MBG
MyBatis Generator,简称 MBG,是一个专门为 MyBatis 框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件、接口以及 bean 类。支持基本的增删改查,以及 QBC 风格的条件查询。但是表连接、存储过程等这些复杂 SQL 的定义需要我们手工编写。
mybatis-generator-core-1.3.2.jar
MBG 配置文件
- javaModelGenerator 配置 JavaBean 的生成策略
- sqlMapGenerator 配置 SQL 映射文件的生成策略
- javaClientGenerator 配置 Mapper 接口的生成策略
- table 配置要逆向解析的数据表
- tableName:表名
- domainObjectName:对应的 JavaBean 名字
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--
targetRuntime
MyBatis3Simple:基础版 CRUD
MyBatis3:复杂版(带动态 SQL) CRUD
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- jdbcConnection:指导连接到哪个数据库 -->
<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql:///test"
userId="root"
password="root">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--
javaModelGenerator:生成 POJO
targetPackage:生成的 POJO 放在哪个包
targetProject:放在哪个工程下
-->
<javaModelGenerator
targetPackage="cn.edu.nuist.bean"
targetProject=".src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--sqlMapGenerator:SQL 映射文件生成器;指定映射文件生成的地方 -->
<sqlMapGenerator
targetPackage="cn.edu.nuist.mapper"
targetProject=".conf">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- javaClientGenerator:Mapper<I> 生成的地方 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.edu.nuist.mapper"
targetProject=".src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--
table:指定要逆向生成哪个数据表
tableName="t_cat":表名
domainObjectName="":这个表对应的对象名
-->
<table tableName="teacher" domainObjectName="Teacher"></table>
<table tableName="emp" domainObjectName="Employee"></table>
<table tableName="dept" domainObjectName="Department"></table>
</context>
</generatorConfiguration>
运行代码生成器生成代码
public class TestMBG {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator
= new MyBatisGenerator(config, callback, warnings);
// 代码生成
myBatisGenerator.generate(null);
System.out.println("生成了!");
}
}