note
- SqlSessionFactory 它是一个线程安全的
- SqlSession 线程非安全,不能做类的公用变量
- 当数据库字段和实体对象名称不一至时,通过sql的字段命名别名,别名跟实体对象属性一致
jar包(mybatis3.2.2)
- mybatis-3.2.2.jar 核心驱动
- asm-3.3.1.jar
- cglib-2.2.2.jar
- commons-logging-1.1.1.jar
- javassist-3.17.1-GA.jar
- log4j-1.2.17.jar
- slf4j-api-1.7.5.jar
- slf4j-log4j12-1.7.5.jar
- mysql-connector-java-5.1.26.jar 数据库驱动
sqlMapConfig.xml
- 配置内容:
1) 配置事务
2) 配置数据源
3) 声明mapper文件
<?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>
<!-- 配置数据源,事务 -->
<environments default="test">
<environment id="test">
<!-- 事务:JDBC/MANAGED-自己管理去 -->
<transactionManager type="JDBC"/>
<!-- 数据源:POOLED/UNPOOLED/JNDI -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?charsetEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<environment id="deploy">
<!-- 事务:JDBC/MANAGED-自己管理去 -->
<transactionManager type="JDBC"/>
<!-- 数据源:POOLED/UNPOOLED/JNDI -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?charsetEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件mapper -->
</configuration>
mapper.xml
- 命名空间,在不同的mapper,但mapper中的方法同名,靠命名空间区分
- resultMap不是必须,可以不写,前提:表和实体的属性一样。(mybatis底层自动生成resultMap)
- 它通过数据结果集来映射的。Hibernate它是通过数据库表字段来映射的。
- 关联关系:
A.对一association javaType
B.对多 collection ofType
jdbcType
它是指定当NAME为null时,给jdbc驱动程序告诉它,它针对的数据库字段的类型。(Oracle)
<update id="update" parameterType="cn.itcast.domain.Person">
update person
<set>
<if test="name!=null">user_name=#{name,jdbcType=VARCHAR},</if>
<if test="age!=null">age=#{age},</if>
<if test="remark!=null">remark=#{remark},</if>
</set>
where id = #{id}
</update>
- Mapper中写SQL获取参数
+ #{} 它会自动根据参数类型做封装。例如对字符串类型,两边加单撇;对整数类型直接使用;好处防止SQL注入(推荐)
+ ${} 将用户填入的参数直接拼接到SQL。(字符串直接拼接)坏处:SQL注入;例如:拼接order by条件(特殊的地方)
- SQL中含有特殊字符
<if test="ageEnd!=null"><![CDATA[and age <=]]> #{ageEnd}</if>
- 动态SQL
+ <if> 判断条件
+ <where> 自动删除最前面的and 或者or,实际开发中常用where 1=1
+ <set> 它自动删除最后一个set值的逗号,修改时,修改参数不同
+ <foreach> 主要应用在in子查询,批量删除时候,array,list,map
- 常规的标签
+ <select> 查询,参数map;返回值List(selectList),可以是一个值(selectOne)
+ <insert> 新增,参数po;新增时习惯写所有的字段
+ <update> 修改,参数po;修改时习惯使用动态sql语句
+ <delete> 删除,参数 int,string,array,list,map
-
参数:
- parameterMap 废除,早期使用
- parameterType 简单变量int/string/double/po/map
-
返回值:
- resultType 简单变量int/string/double/po/map
- resultMap 它是mybatis核心;实际resultType使用时,底层自动转为resultMap;在数据库结果集和实体对象加了一层。例如:数据库字段USER_NAME,实体中name;通过它mybatis可以找到映射的规则;它可以配置关联关系;mybatis自动将大大的结果集分拆到各个对象中。(难点)
- SQL返回的结果集中字段不能有重名的,如果有,必须设置别名,通过resultMap映射时进行转化。
<?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="com.fuyi.mapper.PersonMapper">
<!-- 查询,注意Mybatis中如果有填写集合类型,只填写集合中元素的类型 -->
<sql id="cols">id,name,age</sql>
<resultMap type="com.fuyi.domain.User" id="userRM">
<id property="id" column="ID" />
<result property="name" column="NAME" />
<result property="age" column="AGE" />
</resultMap>
<resultMap type="com.fuyi.domain.User" id="userAndInfoRM"
extends="userRM">
<association property="userInfo" javaType="com.fuyi.domain.UserInfo">
<id property="id" column="info_id" />
<result property="jobDate" column="job_date" />
<result property="position" column="POSITION" />
</association>
</resultMap>
<resultMap type="com.fuyi.domain.User" id="userAndBookRM"
extends="userAndInfoRM">
<collection property="book" ofType="com.fuyi.domain.Book">
<id property="id" column="book_id" />
<result property="title" column="title" />
<result property="publish" column="publish" />
</collection>
</resultMap>
<select id="findUserAndBook" resultMap="userAndBookRM">
select p.id, p.name,
p.age, p.info_id, p.job_date,p.position, b.id as book_id, b.title,
b.publish
from (select u.id,u.name,u.age,i.id as info_id,i.job_date,i.position
from
user u left outer join user_info i on u.id = i.user_id ) p LEFT JOIN
book b on p.id = b.user_id;
</select>
<select id="findUserAndInfo1" resultMap="userAndInfoRM">
select
u.id,u.name,u.age,i.id as info_id,i.job_date,i.position
from user u
left outer join user_info i on u.id = i.user_id
</select>
<!-- 查询,注意Mybatis中如果有填写集合类型,只填写集合中元素的类型 -->
<select id="find" parameterType="map" resultType="User">
select
<include refid="cols" />
from user
<where>
<if test="name!=null">and name like #{name}</if>
<if test="age!=null">and age = #{age}</if>
</where>
</select>
<select id="get" parameterType="int" resultType="com.fuyi.domain.User">
select * from
user
</select>
<insert id="insert" parameterType="com.fuyi.domain.User">
insert into user(name, age)
values(#{name}, #{age})
</insert>
<update id="update" parameterType="com.fuyi.domain.User">
update user
<!-- name = #{name}, age = #{age} -->
<set>
<if test="name!=null"> name = #{name},</if>
<if test="age!=null"> age = #{age},</if>
</set>
where id = #{id}
</update>
<delete id="deleteById" parameterType="int">
delete from user
where id in
<foreach collection="array" item="ind" open="(" close=")"
separator=",">
#{ind}
</foreach>
</delete>
<delete id="deleteList" parameterType="int">
delete from user
where id in
<foreach collection="list" item="ind" open="(" close=")"
separator=",">
#{ind}
</foreach>
</delete>
<delete id="deleteMap" parameterType="map">
delete from user
where id in
<foreach collection="ids" item="id" open="(" close=")"
separator=",">
#{id}
</foreach>
</delete>
<select id="count" resultType="int">
select count(*) from user
</select>
</mapper>
测试
public class TestMybatis {
@Test
public void init() throws IOException{
InputStream is = Resources.getResourceAsStream(classpath:mybatis/sqlMapConfig.xml);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
//如何访问mapper中的方法呢? 规则:命名空间+.+id
List<Person> personList = session.selectList("com.fuyi.mapper.PersonMapper.find");
System.out.println(personList.size());
for(Person p : personList){
System.out.println(p);
}
}
}
mapper接口开发
- 规则
- 接口名称必须和mapper文件名称相同
- 接口包路径和命名空间一致(接口文件和mapper文件在一起)
- 接口中要声明的方法名和某个sql配置的id属性一致
- 参数和返回值,要按java规则写
- Test
public class TestMapperInterface {
private SqlSessionFactory factory;
@Before //最先执行,初始化SessionFactory
public void init() throws IOException{
String resource = "sqlMapConfig.xml";
InputStream is = Resources.getResourceAsStream(resource);
factory = new SqlSessionFactoryBuilder().build(is);
}
@Test
public void testFind(){
SqlSession session = factory.openSession();
//获取接口对象
PersonMapper mapper = session.getMapper(PersonMapper.class);
Map map = new HashMap();
map.put("name", "'t%'");
List<Person> pList = mapper.find(map);
System.out.println(pList.size());
}
}
缓存
- 一级缓存Hibernate,session级别
- 二级缓存Hibernate,sessionFactory级别
- Mybatis它和hibernate一样
- 一级缓存默认开启
public void cacheLevel1(){
SqlSession session = factory.openSession();
PersonMapper mapper = session.getMapper(PersonMapper.class);
Map map = new HashMap();
map.put("name", "'tony'");
List<Person> personList = mapper.find(map);
System.out.println(personList.size());
PersonMapper mapper2 = session.getMapper(PersonMapper.class);
List<Person> personList2 = mapper2.find(map);
System.out.println(personList2.size());
//结果只发出一条sql查询
}
- 二级缓存默认不开启
开启方式:在mapper.xml中添加
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
在实际开发中,经过在线上压力测试,找到一个符合当前客户运行环境下最恰当的值。
public void cacheLevel2(){
SqlSession session = factory.openSession();
PersonMapper mapper = session.getMapper(PersonMapper.class);
Map map = new HashMap();
map.put("name", "'tony'");
List<Person> personList = mapper.find(map);
System.out.println(personList.size());
session.close(); //关闭session
session = factory.openSession();
PersonMapper mapper2 = session.getMapper(PersonMapper.class);
List<Person> personList2 = mapper2.find(map);
System.out.println(personList2.size());
// 关闭session后,结果只发出一条sql查询
}
默认mybatis二级缓存一般使用第三方Ehcache
- Ehcache 单机
- Momeycache 集群
- 导入Ehcache的jar包
- ehcache-core-2.6.5.jar
- mybatis-ehcache-1.0.2.jar
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
- copy ehcache-failsafe.xml rename ehcache.xml
拦截器interceptor
- Mybatis 分页
1) 自定义一个拦截器类,实现interceptor接口
2) 插件,在sqlMapConfig.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>
<!-- 分页拦截器,拦截用户提交的查询,只查询当前页数据;提高响应速度。 -->
<plugins>
<plugin interceptor="cn.itcast.jk.pagination.PageInterceptor">
<property name="databaseType" value="oracle"/>
</plugin>
</plugins>
</configuration>
- Springmvc 拦截器
性能监控
开发步骤:
1、编写拦截器,记录Controller方法执行时间
public class TimerInterceptor implements HandlerInterceptor {
private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("WatchExecuteTime");
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
long beginTime = System.currentTimeMillis(); //开始时间
startTimeThreadLocal.set(beginTime);
return true;
}
public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object arg2, Exception arg3) throws Exception {
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTimeThreadLocal.get();
System.out.println(String.format("%s execute %d ms." , req.getRequestURI() , executeTime));
}
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
}
}
2、在springmvc-servlet.xml文件中配置拦截器
对多个controller进行指定方法的拦截
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/cargo/export/list.action"/>
<bean class="cn.itcast.jk.interceptor.TimerInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/cargo/packinglist/list.action"/>
<bean class="cn.itcast.jk.interceptor.TimerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
对多个controller的所有方法拦截
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/cargo/export/*"/>
<bean class="cn.itcast.jk.interceptor.TimerInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/cargo/packinglist/*"/>
<bean class="cn.itcast.jk.interceptor.TimerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
对某目录下的controller进行拦截
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/cargo/**"/>
<bean class="cn.itcast.jk.interceptor.TimerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
拦截整个项目的所有controller
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.itcast.jk.interceptor.TimerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
spring + mybatis
- sqlMapConfig.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>
</configuration>
- beans.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 1.包扫描,service dao -->
<context:component-scan base-package="cn.itcast.ssm.dao,cn.itcast.ssm.service"/>
<!-- 2.jdbc.properties属性配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 3.数据源 DataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverclass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 4.SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- spring和mybatis整合 -->
<!-- 1)引入mybatis核心配置文件 -->
<property name="configLocation" value="classpath:sqlMapCongfig.xml"/>
<!-- 2)扫描指定目录下的所有Mapper.xml -->
<property name="mapperLocations" value="classpath:cn/itcast/ssm/mapper/*.xml"/>
</bean>
<!-- 5.事务 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="view*" read-only="true"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* cn.itcast.ssm.service.*.*(..))" id="pointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
</aop:config>
</beans>
- springmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
<!-- 1.包扫描controller -->
<context:component-scan base-package="cn.itcast.ssm.web.controller"/>
<!-- 2.内部资源视图解析器 -->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages"/>
<property name="suffix" value=""/>
</bean>
</beans>
- 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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="taotao" version="2.5">
<display-name>yycg</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 解决post乱码 -->
<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>
<!-- springmvc的前端控制器 -->
<servlet>
<servlet-name>yycg</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>yycg</servlet-name>
<!-- 做伪静态,做搜索引擎优化(SEO)
<url-pattern>*.html</url-pattern>
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>