MyBatis是GitHub上一个开源框架,它支持定制化 SQL、存储过程以及高级映射的优秀的持久层(sql映射)框架。
Mybatis与JdbcTemplate的区别在于,后者是一个工具,只对一些简单的功能进行了封装,且是硬编码在程序中,数据库层的和java编码耦合,不利于修改。但前者是sql映射整体解决方案,考虑缓存、考虑异常处理问题、考虑部分字段映射问题等等问题
与Hibernate对比:
Hibernate也是一个与数据库交互的框架(ORM(Object Relation Mapping:对象关系映射)),它是一个全自动的框架,只需要创建好javaBean对象,其他的事情都交由Hibernate。但同时它不能自己定制sql语句,如果要定制sql,就要学习HQL语言,增加了学习成本。而且全映射框架在只需要查询一两个字段,会严重影响效率,因为类中所有的字段都要与表对应。
Mybatis小结
- 1.开发环境配置
- 2.Mybatis全局配置文件细节
- 1)properties 属性
- 2)settings 设置:改变MyBatis运行时行为
- 3)typeAliases 别名处理器:为Java类型设置一个简单的别名
- 4)typeHandlers 类型处理器:配置自定义类型处理器,实现 org.apache.ibatis.type.TypeHandler 接口,或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler
- 5)objectFactory 对象工厂
- 6)plugins插件
- 7)environments 环境:将 SQL 映射应用于多种数据库之中
- 8)databaseIdProvider 数据库厂商标识
- 9)mappers 映射器:指明sql映射文件的位置
- 3.sql映射文件
- 4.MyBatis缓存机制
- 5.MBG逆向工程
- 6.SSM整合
1.开发环境配置
1)导入包:
mysql-connector-java-5.1.37-bin.jar
mybatis-3.4.1.jar
log4j-1.2.17.jar(在mybatis关键的环节就会有日志打印)
maven配置:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
(1)日志配置文件
log4j依赖类路径下一个log4j.properties配置文件
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
### 2)建立数据库、Dao接口、JAVABean对象
(2)Sql映射文件
<?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">
<!--namespace:名称空间;写接口的全类名,相当于告诉MyBatis这个配置文件是实现哪个接口的; -->
<mapper namespace="com.dao.EmployeeDao">
<!-- public Employee getEmpById(Integer id); -->
<!--
select:用来定义一个查询操作
id:方法名,相当于这个配置是对于某个方法的实现
resultType:指定方法运行后的返回值类型,全类名;(查询操作必须指定的)
#{属性名}:代表取出传递过来的某个参数的值,如果传入一个JAVABEAN对象,直接写对象中的属性名,不要写成级联属性
-->
<select id="getEmpById" resultType="com.bean.Employee">
select * from t_employee where id=#{id}
</select>
<!-- public int updateEmp(Employee employee); -->
<!--
增删改无需指定返回类型resultType,返回影响行数
mybatis自动封装类型:int、long直接封装,boolean返回类型如果影响0行则返回false
#{属性名}:代表取出传递过来的某个参数的值
-->
<select id="updateEmp">
UPDATE t_employee SET name=#{name},gender=#{gender}
</select>
</mapper>
(3)全局配置文件
<?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>
<!-- 配置日志文件-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
</databaseIdProvider>
<!-- 引入我们自己编写的每一个接口的实现文件 -->
<mappers>
<!--resource:表示从类路径下开始找资源 -->
<mapper resource="mybatis/EmployeeDao.xml"/>
</mappers>
</configuration>
4)测试
public void init(){
//1、先创建一个sqlSessionFactory
String resource = "mybatis-config.xml";
SqlSession sqlSession =null;
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = ssf.openSession();
EmployeeDao empDao = sqlSession.getMapper(EmployeeDao.class);
Employee emp = empDao.getUserById(1);
System.out.println(emp);
} catch (IOException e) {
e.printStackTrace();
sqlSession.close();
}
}
两个细节:1.获取到的是接口的代理对象,是mybatis自动创建的
2.SqlSessionFactory创建SqlSession对象,Factory只需要创建一次就行,但是每进行一次会话就应该创建一个SqlSession对象
2.Mybatis全局配置文件细节
configuration子标签:按照顺序配置,如果顺序错误,就会报“The content of element type “configuration” must match “(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)”.”错误
1)properties 属性
和spring的context-placeholder一样,用来引用外部配置文件
- resource:引用类路径下文件
- url:引用磁盘路径或网络路径资源
2)settings 设置:改变MyBatis运行时行为
例如JAVA命名遵循驼峰命名规则,但是sql不区分大小写,如果要在sql中列名用大写,则在前面加一个“_”,例如loginAccount(JAVA)对应login_account(mysql),就要在设置中配置用驼峰命名规则才能查询到正确结果
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3)typeAliases 别名处理器:为Java类型设置一个简单的别名
<typeAliases>
<typeAlias type="com.dao.UserDao" alias="userDao"/>
</typeAliases>
还可以批量取别名(给某个包下所有类取别名,默认就是个这个包下各自的类名):
<typeAliases>
<typeAlias type="com.dao"/>
</typeAliases>
但如果要为该包下某个类取一个别名而非默认类名,可以在该类上加一个注解@Alias,括号内的就为该类的别名
不过推荐还是配置为全类名,方便定位。而且取别名的时候不能占用系统已有的类型别名,比如date、_byte等
4)typeHandlers 类型处理器:配置自定义类型处理器,实现 org.apache.ibatis.type.TypeHandler 接口,或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API)
5)objectFactory 对象工厂
默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现。但是一般不用。
6)plugins插件
插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行。
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
7)environments 环境:将 SQL 映射应用于多种数据库之中
在实际开发中,一般有多种数据库环境,比如开发环境,测试环境要切换数据库,用default属性切换默认数据库。
每个数据库对应一个 SqlSessionFactory 实例,为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。
<environments default="development">
<!--id是一个环境的唯一标识-->
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
属性:
1.事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type=“[JDBC|MANAGED]”):
JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 J2EE应用服务器的上下文)。默认情况下它会关闭连接。
2.数据源(dataSource)
1)UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
2)POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
3)JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。
实际开发中,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
8)databaseIdProvider 数据库厂商标识
databaseIdProvider 的type是固定的,为DB_VENDOR。 DB_VENDOR 实现会将 databaseId 设置为 DatabaseMetaData#getDatabaseProductName() 返回的字符串。由于通常情况下这些字符串(name属性)都非常长,而且相同产品的不同版本会返回不同的值,可以通过设置属性别名(value属性)来使其变短。
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="ora"/>
<property name="SQL Sever" value="sqlserver"/>
</databaseIdProvider>
如果切换数据库,会分别执行该databaseID下的sql语句,如果能精确匹配就匹配,如果不能匹配就是用默认的(第一个)
<delete id="deleteEmployee" >
DELETE FROM t_employee WHERE id=#{id}
</delete>
<delete id="deleteEmployee" databaseId="mysql">
DELETE FROM t_employee WHERE id=#{id}
</delete>
<delete id="deleteEmployee" databaseId="ora">
DELETE FROM t_employee WHERE id=#{id}
</delete>
9)mappers 映射器:指明sql映射文件的位置
- url:使用完全限定资源定位符(URL)从磁盘或网络路径
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
- resource:使用相对于类路径的资源引用
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
- class:使用映射器接口类的完全限定类名
<mappers>
<mapper class="com.bean.Employee"/>
</mappers>
注意如果使用类名注册,则Dao接口文件应和sql映射文件需要在同一包内,且文件名要保持一致
如下图所示的UserDao和UserDao.xml:
- 也可以直接在Dao接口的方法上注解
public interface UserDao {
@Select("select * from user where id=#{id}")
UserInfo getUserById(Integer id);
}
这样在全局配置文件中的mappers映射标签要使用class,因为没有对应的sql映射文件
- 还可以将包内的映射器接口实现全部注册为映射器
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
此时也需要将配置文件和接口文件放在同一包目录下且同名,但是可以在conf文件夹下建一个与接口文件相同的包路径,这样就可以分开放置配置文件和接口类了
3.sql映射文件
映射文件指导着MyBatis如何进行数据库增删改查
1)增删改标签:insert/delete/update
标签属性
id:与方法名相同,所以不能出现方法重载
useGeneratedKeys底层调用的是原生jdbc获取自增主键的方法
keyProperty指明自增的id封装给哪个属性
<!-- public int insertEmployee(Employee employee); -->
<insert id="insertEmployee" useGeneratedKeys="true"
keyProperty="id">
INSERT INTO t_employee(empname,gender,email)
VALUES(#{empName},#{gender},#{email})
</insert>
这样对于插入数据时没有插入主键值主键值也会自动自增
@Test
public void test01() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
Employee employee = new Employee(null, "haah", "aaa", 0);
employeeDao.insertEmployee2(employee);
System.out.println(employee.getId());
openSession.commit();
} finally {
openSession.close();
}
}
对于不支持主键自增的数据库,可以直接写一个子句查询其主键id :,然后进行主键自增:在sql插入语句执行前执行查询最大id,然后将其写入到id属性中
<!-- public int insertEmployee2(Employee employee); -->
<insert id="insertEmployee2">
<!--查询主键
order="BEFORE":在核心sql语句之前先运行一个查询sql查到id;将查到的id赋值给javaBean的哪个属性-->
<selectKey order="BEFORE" resultType="integer" keyProperty="id">
select max(id)+1 from t_employee
</selectKey>
INSERT INTO t_employee(id,empname,gender,email)
VALUES(#{id},#{empName},#{gender},#{email})
</insert>
2)select标签
返回值类型总结
(1)返回List:直接写List泛型类型
<!-- List<UserInfo> getUserAll();-->
<select id="getUserAll" resultType="com.domain.UserInfo">
select * from user
</select>
(2)返回一条记录Map:直接写Map
map集合中,列名作为键名,值作为map的值
<!--Map<String,Object> getUserMapById(Integer id);-->
<select id="getUserMapById" resultType="map">
select * from user where id=#{id}
</select>
结果:
{qq=8402349, password=123, address=地球, gender=男, name=zhangsan, id=1, age=18, email=sdfdsf, username=lili}
(3)返回多条记录Map:用@MapKey指定键名,返回类型为值类型
使用@MapKey指定返回的map使用哪个属性作为键名,但是要保证该属性是唯一性
@MapKey("name")
Map<String,UserInfo> getUserMapAll();
<!-- Map<Integer,UserInfo> getUserMapAll();-->
<select id="getUserMapAll" resultType="com.domain.UserInfo">
select * from user
</select>
(4)自定义封装规则
如果JavaBean的属性名和数据库的列名不同,则需要自定义封装规则,例如在javabean中属性为name,age,gender但是在数据库中列名为cname,cage,cgender,此时只能取别名或自定义结果集
- 取别名
<select id="getUserById" resultType="com.domain.UserInfo">
select cname name,cgender gender from user where id=#{id}
</select>
- 自定义结果集(ResultMap)
即ResultType使用的Mybatis默认的封装规则,如果需要自定义封装规则时,则使用ResultMap定义返回结果:
id定义主键封装规则
result定义其他键封装规则
<!-- UserInfo getUserById(Integer id);-->
<select id="getUserById" resultType="userResMap">
select * from user where id=#{id}
</select>
<resultMap id="userResMap" type="com.domain.UserInfo">
<id property="id" column="cid"/>
<result property="name" column="cname"/>
<result property="gender" column="cgender"/>
<result property="age" column="cage"/>
</resultMap>
- 返回类型中存在属性也是对象的情况,在数据库中就是存在外键情况
public class Lock {
private Integer id;
private String lockName;
private List<Key> keys;
}
public class Key {
private Integer id;
private String keyName;
private Lock lock;//属性也是一个对象
}
1.使用级联属性
<!-- getKeyById(Integer) -->
<!-- 查询列:id keyname lockid lid lockName -->
<select id="getKeyById" resultMap="mykey">
select k.id,k.`keyname`,k.`lockid`,
l.`id` lid,l.`lockName` from t_key k
left join t_lock l on k.`lockid`=l.`id`
where k.`id`=#{id}
</select>
<resultMap type="com.bean.Key" id="mykey">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<result property="lock.id" column="lid"/>
<result property="lock.lockName" column="lockName"/>
</resultMap>
2.使用association标签定义嵌套结果集—联合查询(mybatis推荐)
<resultMap type="com.bean.Key" id="mykey">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<!-- 接下来的属性是一个对象,自定义这个对象的封装规则;
使用association表示联合了一个对象 -->
<!-- javaType:指定这个属性的类型 -->
<association property="lock" javaType="com.bean.Lock">
<!-- 定义lock属性对应的这个Lock对象如何封装 -->
<id property="id" column="lid"/>
<result property="lockName" column="lockName"/>
</association>
</resultMap>
3.使用collection标签定义集合的封装规则—联合查询
<!-- public Lock getLockById(Integer id);
id lockName kid keyname lockid
-->
<select id="getLockById" resultMap="mylock">
select l.*,k.id kid,k.`keyname`,k.`lockid` from t_lock l
left join t_key k on l.`id`=k.`lockid`
where l.id=#{id}
</select>
<resultMap type="com.bean.Lock" id="mylock">
<id property="id" column="id"/>
<result property="lockName" column="lockName"/>
<!--
collection:定义集合元素的封装
property="":指定哪个属性是集合属性
javaType:association中指定对象类型;
ofType="":指定集合里面元素的类型
-->
<collection property="keys" ofType="com.bean.Key">
<!-- 标签体中指定集合中这个元素的封装规则 -->
<id property="id" column="kid"/>
<result property="keyName" column="keyname"/>
<!--可以不定义lock属性-->
<!--<association property="lock" javaType="com.bean.Lock">-->
<!--<id property="id" column="lid"/>-->
<!--<result property="lockname" column="lockName"/>-->
<!--</association>-->
</collection>
</resultMap>
4.select分步查询
比如要查询某个钥匙可以开哪把锁,可以先查询出key对象,再根据key中lockid查询锁
association分步查询:
<!-- public Key getKeyByIdSimple(Integer id); -->
<!--
private Integer id;
private String keyName;
private Lock lock;
-->
<!-- id keyname lockid -->
<select id="getKeyByIdSimple" resultMap="mykey02">
select * from t_key where id=#{id}
</select>
<resultMap type="com.bean.Key" id="mykey02">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<!--告诉mybatis自己去调用一个查询查锁子
select="":指定一个查询sql的唯一标识;mybatis自动调用指定的sql将查出的lock封装进来
lockDao.xml中方法:public Lock getLockByIdSimple(Integer id);需要传入锁子id
告诉mybatis把哪一列的值传递过去
column:指定将哪一列的数据传递过去
fetchType:覆盖全局配置文件的延迟加载属性
-->
<association property="lock"
select="com.dao.LockDao.getLockByIdSimple"
column="lockid" fetchType="lazy"></association>
</resultMap>
collection分步查询:
<!-- public Lock getLockByIdByStep(Integer id);
id lockName
1 1号锁
-->
<select id="getLockByIdByStep" resultMap="mylockstep">
select * from t_lock where id=#{id}
</select>
<!-- collection分步查询 -->
<resultMap type="com.bean.Lock" id="mylockstep">
<id property="id" column="id"/>
<result property="lockName" column="lockName"/>
<!-- collection指定集合类型的属性封装规则 -->
<collection property="keys"
select="com.dao.KeyDao.getKeysByLockId"
column="{id=id}"></collection>
<!-- 在分步查询的时候,如果有多个列名需要传入:column={参数key1=列名1,参数key2=列名2....} -->
</resultMap>
这样mysql会执行两次sql语句,如果只需要查询钥匙的名字,写这么多sql查询会影响效率,所以可以在mybatis的全局配置文件中设置延迟加载。例如,调用getLockByIdByStep获得的Lock对象,如果只是获得Lock对象的id或者lockname,则不会进行分步查询,调用getKeysByLockId方法,而只执行select * from t_lock where id=#{id}语句
全局配置中的lazyLoadingEnabled是控制association和collection标签的对象是否懒加载,而aggressiveLazyLoading是控制拥有懒加载特性的对象是否延迟加载,true表示如果对具有懒加载特性的对象的任意调用都会导致这个对象的完整加载,即并不会延迟加载,false表示每种属性按照需要加载。
一般来说简单查询和复杂查询写成两个方法比较好,复杂查询写成联合查询
3)cache/cache-ref:和缓存有关
4)resultMap标签:见select标签自定义封装规则
5)sql标签:查看动态sql的sql标签
6)databaseId标签:指定这个CRUD属于哪个数据库的
7)Dao方法参数的映射总结
(1)单参数
- 基本类型取值:#{任意名称}
- POJO对象取值: #{属性名}
(2)多参数
- 0,1…(参数索引)或者param1,param2…(param序号)
<!-- public Employee getEmpByIdAndEmpName(Integer id,String empName);-->
<select id="getEmployeeByIdAndEmpName" resultType="com.bean.Employee">
select * from t_employee where id = #{param1} and empname = #{param2}
</select>
原理:传入多参数时,MyBatis会自动的将这些参数封装到一个map集合中,键名为参数的索引和param序号,所以#{键名}就相当于取参数值
- @Param(命名参数)指定参数的名称(常用)
指定封装为Map集合时的键名而非用默认键名
注意:对于多个参数方法,如果某些参数加了@Param而有些没有加,则可以混合取值:
(3)传入Map
直接使用键名:#{键名}
<!-- public Employee getEmployeeByIdAndEmpName(Map<String, Object> map); -->
<select id="getEmployeeByIdAndEmpName" resultType="com.bean.Employee">
select * from ${tableName} where id=#{id} and empname=#{empName}
</select>
public void test02() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("empName", "admin");
map.put("tableName", "t_employee");
Employee name = employeeDao.getEmployeeByIdAndEmpName(map);
System.out.println(name);
} finally {
openSession.close();
}
}
(4)传入参数时,设置参数属性
#{key}取值的时候可以设置一些属性,例如:id=#{id,jdbcType=INT}
属性类型:javaType、jdbcType(常用)、mode、numericScale、resultMap、typeHandler、jdbcTypeName、expression
Tips:1.默认不指定jdbcType,万一传入的数据是null,mysql插入null没问题,Oracle不知道null到底是什么类型会报错。所以上面的例子如果id为integer类型传入null值,还是需要指定jdbcType。
2.mode 属性允许指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像在获取输出参数时所期望的那样。
(5)传入参数有两种取值方式:#{}和${}
#{属性名}:是参数预编译的方式,参数的位置都是用?替代,参数后来都是预编译设置进去的。不会有sql注入问题,所以安全
${属性名}:不是参数预编译,而是直接和sql语句进行拼串,不安全。但是只有参数位置传值才能预编译,所以如果是表名则需用此方式。
8)动态sql
动态 SQL是MyBatis强大特性之一,极大的简化我们拼装SQL的操作。动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。
MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。
OGNL( Object Graph Navigation Language )是一种对象图导航语言,这是一种强大的
表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的EL,SpEL等
在mybatis中,不止传入的参数可以用来做判断,额外还有两个东西可以用来判断
_parameter:代表传入来的参数
1)、传入了单个参数:_parameter就代表这个参数
2)、传入了多个参数:_parameter就代表多个参数集合起来的map
<if test="_parameter!=null">id=#{id}</if>
_databaseId:代表当前数据库环境,如果配置了databaseIdProvider:_databaseId就有值
<if test="_databaseId='mysql'">select * from mysqltable</if>
<if test="_databaseId='ora'">select * from oracletable</if>
(1)if
<!-- UserInfo getUserByIf(UserInfo user);-->
<select id="getUserByIf" resultType="com.domain.UserInfo">
select * from user where
<!-- test中传入的为判断条件,为OGNL表达式,如果写&或“等,需要转义-->
<if test="id!=null">id>#{id} and </if>
<if test="name!=null and name !=''">name like #{name} and </if>
<if test="age!=null">age >15 </if>
</select>
@Test
public void test03(){
SqlSession sqlSession=null;
try {
sqlSession = ssf.openSession();
UserDao user = sqlSession.getMapper(UserDao.class);
UserInfo u = new UserInfo();
u.setAge(15);
u.setId(0);
u.setName("%张%");
UserInfo userinfo = user.getUserByIf(u);
System.out.println(userinfo);
}
finally {
sqlSession.close();
}
}
//日志信息:
Preparing: select * from user where id>? and name like ? and age >15
注意:if标签不会自动去除里面的连接词,所以使用时要小心
添加where标签:
<select id="getUserByIf" resultType="com.domain.UserInfo">
select * from user
<!-- 在where标签中必须要返回一个条件,且如果子句以and或or开头,会自动去除-->
<where>
<if test="id!=null">id>#{id} </if>
<if test="name!=null and name !=''">and name like #{name} </if>
<if test="age!=null">and age > 15</if>
</where>
</select>
@Test
public void test03(){
SqlSession sqlSession=null;
try {
sqlSession = ssf.openSession();
UserDao user = sqlSession.getMapper(UserDao.class);
UserInfo u = new UserInfo();
u.setAge(15);
// u.setId(0);
u.setName("%张%");
UserInfo userinfo = user.getUserByIf(u);
System.out.println(userinfo);
}
finally {
sqlSession.close();
}
}
//日志打印
Preparing: select * from user WHERE name like ? and age > 15
(2)choose
相当于if/else,当第一个when标签满足,后面的都不进入了
当没有一个when标签满足,则进入otherwise
<!-- UserInfo getUserByIf(UserInfo user);-->
<select id="getUserByIf" resultType="com.domain.UserInfo">
select * from user
<where>
<choose>
<when test="id!=null">id=#{id}</when>
<when test="name!=null and name!=''">name=#{name}</when>
<otherwise>age>15</otherwise>
</choose>
</where>
</select>
(3)trim
<!-- UserInfo getUserByIf(UserInfo user);-->
<select id="getUserByIf" resultType="com.domain.UserInfo">
select * from user
<!--prefix:前缀,一般以where作为前缀,这样即使后面子句为空也不会报错
prefixOverrides:去除前缀多余字符
suffix:后缀
suffixOverrides:去除后缀多余字符
-->
<trim prefix="where" prefixOverrides="and" suffixOverrides="and">
<if test="id!=null">id>#{id} and</if>
<if test="name!=null and name !=''"> name like #{name} and</if>
<if test="age!=null"> age > 15 and</if>
</trim>
</select>
(4)foreach
<!--List<UserInfo> getUserByForeach(List<Integer> ids);-->
<select id="getUserByForeach" resultType="com.domain.UserInfo">
select * from user where id in
<!--collection直接写list,如果想取别名,在方法参数前@Param更换即可
collection="":指定要遍历的集合的key
close="":以什么结束
open="":以什么开始
separator="":每次遍历的元素的分隔符
index="i":索引
item:就是保存当前遍历的元素的值;item="变量名":每次遍历出的元素起一个变量名方便引用
如果遍历的是一个list;
index:指定的变量保存了当前索引
item:保存当前遍历的元素的值
如果遍历的是一个map:
index:指定的变量就是保存了当前遍历的元素的key
-->
<foreach collection="list" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</select>
(5)set
自动去除多余逗号
<!--UserInfo updateUserById(UserInfo user);-->
<update id="updateUserById" >
update user
<set>
<if test="age!=null">age=#{age},</if>
<if test="name!=null and name!=''">name = #{name},</if>
</set>
<where>id=#{id}</where>
</update>
(6)bind
将某个变量绑定到固定的表达式中,常用于模糊查询
<!-- void getUserByIf(UserInfo user);-->
<select id="getUserByIf" resultType="com.domain.UserInfo">
select * from user
<bind name="_name" value="'%'+name+'%'"/>
<where>
<if test="id!=null">id=#{id}</if>
<if test="name!=null and name!=''">and name like #{_name}</if>
<if test="age!=null">and age>15</if>
</where>
</select>
(7)sql/include
抽取可重用sql
<sql id="sql1">select * from user</sql>
<!-- UserInfo getUserByIf(UserInfo user);-->
<select id="getUserByIf" resultType="com.domain.UserInfo">
<include refid="sql1"/>
<bind name="_name" value="'%'+name+'%'"/>
<where>
<if test="id!=null">id=#{id}</if>
<if test="name!=null and name!=''">and name like #{_name}</if>
<if test="age!=null">and age>15</if>
</where>
</select>
4.MyBatis缓存机制
MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存,一级缓存是与数据库同一次会话中获得的数据都放入缓存中。
1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
2、二级缓存需要手动开启和配置,他是基于全局级别的缓存。
3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
1)一级缓存
SqlSesion级别的缓存,默认就一直存在,不用开启和关闭,也关闭不了。
机制:只要之前查询过的数据,mybatis就会保存在一个缓存中(Map),下次获取直接从缓存中拿。
@Test
public void test03(){
SqlSession sqlSession=null;
try {
sqlSession = ssf.openSession();
UserDao user = sqlSession.getMapper(UserDao.class);
UserInfo u = new UserInfo();
u.setName("张");
UserInfo userinfo = user.getUserByIf(u);
UserInfo userinfo1 = user.getUserById(1);
UserInfo userinfo2 = user.getUserByIf(u);
System.out.println(userinfo);
}
finally {
sqlSession.close();
}
}
//日志打印
com.dao.UserDao.getUserByIf - ==> Preparing: select * from user WHERE name like ?
com.dao.UserDao.getUserByIf - ==> Parameters: %张%(String)
com.dao.UserDao.getUserByIf - <== Total: 1
com.dao.UserDao.getUserById - ==> Preparing: select * from user where id=?
com.dao.UserDao.getUserById - ==> Parameters: 1(Integer)
com.dao.UserDao.getUserById - <== Total: 0
一级缓存失效的几种情况:
- 1、不同的SqlSession对应不同的一级缓存
- 2、同一个SqlSession但是查询条件不同
- 3、同一个SqlSession两次查询期间执行了任何一次增删改操作:任何一次增删改都会清空缓存
- 4、同一个SqlSession两次查询期间调用 clearCache()方法手动清空
@Test
public void test03(){
SqlSession sqlSession=null;
try {
sqlSession = ssf.openSession();
UserDao user = sqlSession.getMapper(UserDao.class);
UserInfo u = new UserInfo();
u.setName("张");
UserInfo userinfo = user.getUserByIf(u);
sqlSession.clearCache();
UserInfo userinfo1 = user.getUserById(1);
UserInfo userinfo2 = user.getUserByIf(u);
System.out.println(userinfo);
}
finally {
sqlSession.close();
}
}
//日志打印
com.dao.UserDao.getUserByIf - ==> Preparing: select * from user WHERE name like ?
com.dao.UserDao.getUserByIf - ==> Parameters: %张%(String)
com.dao.UserDao.getUserByIf - <== Total: 1
com.dao.UserDao.getUserById - ==> Preparing: select * from user where id=?
com.dao.UserDao.getUserById - ==> Parameters: 1(Integer)
com.dao.UserDao.getUserById - <== Total: 0
com.dao.UserDao.getUserByIf - ==> Preparing: select * from user WHERE name like ?
com.dao.UserDao.getUserByIf - ==> Parameters: %张%(String)
com.dao.UserDao.getUserByIf - <== Total: 1
每次查询操作都会去查找一级缓存中有没有,每个sqlSession都拥有自己的一级缓存
一级缓存的本质就是一个map,所以在查找缓存的时候,方法只要有任何不一样,都不会用这个key
2)二级缓存
- 二级缓存默认不开启,需要手动配置
- MyBatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口
- 二级缓存在 SqlSession 关闭或提交之后才会生效,即一级缓存的数据在 SqlSession 关闭或提交之后会放在二级缓存中,如果sqlSession正在使用,则不会放到二级缓存中
(1)二级缓存的配置
a.全局配置文件中开启二级缓存
<!-- 开启全局缓存开关; -->
<setting name="cacheEnabled" value="true"/>
b.需要使用二级缓存的映射文件处使用<cache/>配置缓存
<mapper namespace="com.dao.UserDao">
<cache/>
<!--UserInfo getUserById(Integer id);-->
<select id="getUserById" resultType="com.domain.UserInfo">
select * from user where id=#{id}
</select>
....
注意:使用二级缓存的JavaBean对象必须实现序列化接口,实现即可,里面并没有方法
(2)cache标签属性
3)执行顺序
- 任何时候查询都会先看二级缓存,如果二级缓存没有再查询一级缓存,如果一级缓存没有则查询数据库将查询结果放入一级缓存中。
- 每一个Dao映射都有自己的一个二级缓存
4)缓存有关设置
- 全局设置二级缓存开关:cacheEnabled
- select标签局部设置是否使用二级缓存:useCache
- C/R/U/D标签设置是否清空二级缓存:flushCache。C/U/D默认为true,select标签默认为false
- sqlSession.clearCache():清空一级缓存
5)整合第三方缓存
MyBatis的缓存库做的不好,所以开放了Cache接口(二级缓存)供第三方整合:
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider
使用方法:
1.导包
ehcache-core-2.6.8.jar(ehcache核心包)
mybatis-ehcache-1.0.3.jar(ehcache的整合包,即实现了cache接口的类,可以直接存取ehcache库)
ehcache要运行还依赖日至包:
slf4j-api-1.7.21.jar
slf4j-log4j12-1.7.21.jar
2.ehcache要工作有一个配置文件,文件名(必须)叫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="D:\44\ehcache" />
<defaultCache
maxElementsInMemory="1"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
<!--
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
-->
3.将cache标签替换,且JavaBean对象不用实现序列化接口了
<!-- 使用mybatis默认二级缓存<cache></cache> -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
4.多个Dao共用同一块缓存
<!-- 和别的dao共用一块缓存-->
<cache-ref namespace="com.dao.UserDao"/>
5.MBG逆向工程
MyBatis Generator:代码生成器,MyBatis官方提供的代码生成器;帮我们逆向生成Mysql代码
正向:
数据库表----javaBean—UserDao—dao.xml
逆向工程:
根据数据表table,逆向分析数据表,自动生成javaBean以及UserDao以及dao.xml
6.SSM整合
1)Eclipse版本
(1)导包
- 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
【测试】
spring-test-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-jsp标准标签库】
jstl.jar
standard.jar
【验证码】
kaptcha-2.3.2.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【和Spring整合包】
【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
- 数据库
mysql-connector-java-5.1.37-bin.jar
c3p0-0.9.1.2.jar
(2)配置文件
a.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>7.SSM</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置Spring容器启动: -->
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<!--指定spring配置文件位置 -->
<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的前端控制器 -->
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<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>
<!-- 两个标准配置-->
<!-- 字符编码 -->
<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>
</web-app>
b.spring.xml
<!-- Spring除过控制器不要,剩下的业务逻辑组件都要,包括dao,包括service -->
<context:component-scan base-package="com.atguigu" >
<!-- 扫描排除不写use-default-filters="false" -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--0、导入外部配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<!--1、配数据源 -->
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
<property name="minPoolSize" value="${jdbc.minPoolSize}"></property>
</bean>
<!--2、配置JdbcTemplate操作数据库。用mybatis了,pass -->
<!--3、配置使用mybatis操作数据库 -->
<!-- 可以根据配置文件得到sqlSessionFactory -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定全局配置文件位置 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<property name="dataSource" ref="ds"></property>
<!-- 指定xml映射文件的位置 -->
<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>
</bean>
<!-- 我们要把每一个dao接口的实现加入到ioc容器,不仅仅是加了这些接口进入容器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定dao接口所在的包 -->
<property name="basePackage" value="com.atguigu.dao"></property>
</bean>
<!-- 上面的MapperScannerConfigurerbean等效于 <mybatis-spring:scan base-package="com.atguigu.dao"/> -->
<!--4、配置事务控制;配置事务管理器,让他控制住数据源里面的链接的关闭和提交 -->
<bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"></property>
</bean>
<!--5、基于xml配置,配置事务;哪些方法切入事务还要写切入点表达式 -->
<aop:config>
<!--配置切入点表达式 -->
<aop:pointcut expression="execution(* com.atguigu.service.*.*(..))" id="txPoint"/>
<aop:advisor advice-ref="myTx" pointcut-ref="txPoint"/>
</aop:config>
<!--6、配置事务增强、事务属性、事务建议
transaction-manager="tm":指定要配置的事务管理器的id
-->
<tx:advice id="myTx" transaction-manager="tm">
<!-- 配置事务属性 -->
<tx:attributes>
<tx:method name="*" rollback-for="java.lang.Exception"/>
<tx:method name="get*" read-only="true"/>
<!-- <tx:method name="insertEmp" isolation="READ_UNCOMMITTED"/> -->
</tx:attributes>
</tx:advice>
c.springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- SpringMVC只扫描控制器;禁用默认的规则 -->
<context:component-scan base-package="com.atguigu" 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>
d.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>
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
2)maven依赖
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<shiro.version>1.2.3</shiro.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>