MyBatis
ORM
ORM:对象关系映射ORM框架
Hibernate(SpringDataJPA)、MyBatisMyBatis介绍
Mybatis就是ORM一种实现的框架 MyBatis完成持久层框架各大ORM框架优缺点
JDBC
优点:操作数据库最底层的技术,所有ORM框架的底层都是jdbc,可以自行封装,满足你的各种需求缺点:编写比较麻烦,重复性高,sql需要写到代码内,sql和代码耦合度比较高,没有缓存,还要自行封装数据
JPA
优点:不懂sql也可以操作数据库,使用简单,不用写sql,自动化,以及世界级缓存缺点:性能太难掌控
MyBatis
优点:可以灵活的操作sql,有缓存支持,不用封装数据,避免jdbc重复性代码缺点:非全自动化
MyBatis入门
导包
asm-3.3.1.jarcglib-2.2.2.jar
commons-logging-1.1.1.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
mybatis-3.2.1.jar
mysql-connector-java-5.1.26-bin.jar
slf4j-api-1.7.2.jar
slf4j-log4j12-1.7.2.jar
maven导包
<!-- 引入数据库驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<!-- 引入mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<!-- 引入junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<!-- 引入log4j包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
编写配置文件
<?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>
<!-- 引入db.properties -->
<properties resource="db.properties"/>
<!-- 取别名-->
<typeAliases>
<typeAlias type="cn.itsource.domain.Product" alias="product"></typeAlias>
</typeAliases>
<environments default="development">
<environment id="development">
<!-- 事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!-- 配置数据库连接 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 引入映射配置 -->
<mapper resource="cn/itsource/domain/ProductMapper.xml"></mapper>
</mappers>
</configuration>
编写映射文件
<mapper namespace="cn.itsource.domain.ProductMapper">
<!--
当domain的字段对应不上数据库表字段时
column 数据库字段名
property 对象字段名
-->
<!-- 查询一条 -->
<select id="queryOne" parameterType="long" resultType="cn.itsource.domain.Product">
select * from product where id = #{id}
</select>
</mapper>
查询一条数据
dao层实现 SqlSession sqlSession = null;
try {
//获取SqlSessionFactory
Reader reader = Resources.getResourceAsReader("MyBatis-ConFig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//获得sqlSession
sqlSession = sqlSessionFactory.openSession();
//查询
return sqlSession.selectOne(NAMESPACE+"queryOne",id);
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if (sqlSession != null)
sqlSession.close();
}
测试类
@Test
public void queryOne() {
Product product = productDao.queryOne(2L);
System.out.println(product);
}
sqlSession工具类抽取
private static SqlSessionFactory sqlSessionFactory = null;
//使用静态代码块,确保SqlSessionFactory只创建一次
static {
try {
//获取SqlSessionFactory
Reader reader = Resources.getResourceAsReader("MyBatis-ConFig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("解析MyBatis的配置文件或者映射文件出现异常:" + e.getMessage());
}
}
public static SqlSession createSqlSession(){
//创建SqlSession对象
return sqlSessionFactory.openSession();
}
SqlSessionFactory是一个重量级对象,创建不容易,因此一般一个项目只创建一次该对象,使用单例创建或静态代码块来创建
而sqlsession是线程不安全的,每个线程都应该有自己的sqlSession对象
添加并返回主键id
<!--
添加一条数据
useGeneratedKeys=true 添加数据并返回id
keyColumn 数据库中主键对应的列
keyProperty 对象对应的主键字段
-->
<insert id="save" parameterType="product" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into product(productName,dir_id,salePrice,supplier,brand,cutoff,costPrice)
values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
添加修改删除都应该有事务
//获取sqlSession
SqlSession sqlSession = MyBatisUtils.createSqlSession();
//添加数据
sqlSession.insert(NAMESPACE+"save",product);
//提交事务
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
sqlSession对象使用完后要记得关闭
MyBatis中为一个类取别名
在MyBatis主配置文件中添加<typeAliases>
<typeAlias type="cn.itsource.domain.Product" alias="product"></typeAlias>
<!-- 为该路径下的 -->
</typeAliases>
即可不用重复写全限定名
<!-- 查询所有数据 -->
<select id="queryAll" resultType="product">
select * from product
</select>
列名与属性名不对应的解决方案resultMap
<!--
当domain的字段对应不上数据库表字段时
column 数据库字段名
property 对象字段名
-->
<resultMap id="productMap" type="product">
<id property="id" column="id"></id>
<result column="productName" property="name"></result>
</resultMap>
<!-- 查询所有数据 -->
<select id="queryAll" resultMap="productMap">
select * from product
</select>
Log4j日志框架
#日志输出优先级
log4j.rootLogger=ERROR, stdout
#输出根
log4j.logger.cn.itsource=TRACE
#输出位置(控制台)
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#输出格式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j配置文件命名一定要是:log4j.properties
上面导包时已经将log4j的包导入了
MyBatis SQL参数传递
$与#
#和$的区别#不是拼接sql,防sql注入
$拼接sql不防sql注入
$可用在分页排序
(多对一)关联映射递
<mapper namespace="cn.itsource.mybatis.domain.ProductMapper">
<!--结果嵌套,只发送一条sql,将查询到的结果指定封装-->
<!--
<resultMap id="productMap" type="cn.itsource.mybatis.domain.Product">
<id property="id" column="id"></id>
<result property="productName" column="productName"></result>
<result property="dir_id" column="dir_id"></result>
<association property="dir" javaType="cn.itsource.mybatis.domain.ProductDir">
<id property="id" column="did"></id>
<result column="dname" property="dirName"></result>
</association>
</resultMap>
<select id="queryAll" resultMap="productMap">
select p.*,d.id did,d.dirName dname from product p join productdir d on p.dir_id = d.id
</select>
-->
<!--嵌套查询-->
<resultMap id="productMap" type="cn.itsource.mybatis.domain.Product">
<id property="id" column="id"></id>
<result property="productName" column="productName"></result>
<result property="dir_id" column="dir_id"></result>
<association property="dir" column="dir_id" select="cn.itsource.mybatis.domain.ProductMapper.queryDir"></association>
</resultMap>
<select id="queryAll" resultMap="productMap">
select * from product
</select>
<select id="queryDir" resultType="cn.itsource.mybatis.domain.ProductDir" parameterType="long">
select * from productdir where id=#{dir_id};
</select>
</mapper>
结果嵌套性能相对高一点,只发送了一条sql
嵌套查询是1+n条sql,发送sql较多,性能相对较低
(一对多)关联映射递
<mapper namespace="cn.itsource.mybatis.domain.DeptMapper">
<!--结果嵌套,只发送一条sql,将查询到的结果指定封装-->
<!--<resultMap id="deptMap" type="cn.itsource.mybatis.domain.Dept">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<collection property="employee" javaType="cn.itsource.mybatis.domain.Employee">
<id property="id" column="eid"></id>
<result column="ename" property="name"></result>
</collection>
</resultMap>
<select id="queryAll" resultMap="deptMap">
select d.*,e.id eid,e.name ename from Dept d join employee e on d.id = e.dept_id
</select>-->
<!--嵌套查询-->
<resultMap id="deptMap" type="cn.itsource.mybatis.domain.Dept">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<collection property="employee" column="id" select="cn.itsource.mybatis.domain.DeptMapper.queryDir"></collection>
</resultMap>
<select id="queryAll" resultMap="deptMap">
select * from dept
</select>
<select id="queryDir" resultType="cn.itsource.mybatis.domain.Dept" parameterType="long">
select * from employee where dept_id=#{id};
</select>
</mapper>
一对多查询时不能使用结果嵌套因为map中不能存在多个key值
要使用查询嵌套
SQL映射器Mapper
MyBatis基于代理机制,可以让我们无需再编写Dao的实现。SqlSession sqlSession = MyBatisUtils.createSqlSession();
SkillsMapper mapper = sqlSession.getMapper(SkillsMapper.class);
Skills skills = mapper.queryOne(1L);
sqlSession.close();
在使用时,映射文件的namespace填写接口绝对路径,方法名要与映射文件的保持一致
Skills queryOne(Long id);
<select id="queryOne" parameterType="long" resultType="cn.itsource.mybatis.domain.Skills">
select * from skills where id = #{id}
</select>
缓存
默认支持一级缓存,二级缓存需要配置,同JPA一致,同一个sqlsession,同一主键id命中二级缓存命中条件,同一SqlSessionFactory,不同的sqlsessin,同一主键id
还需要添加配置
ssm集成
jar包
asm-3.3.1.jarcglib-2.2.2.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
com.springsource.org.apache.commons.fileupload-1.2.0.jar
com.springsource.org.apache.commons.io-1.4.0.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.commons.pool-1.5.3.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
ehcache-2.10.1.jar
freemarker.jar
javamail.jar
javassist-3.17.1-GA.jar
jstl.jarv
log4j-1.2.17.jar
mybatis-3.2.1.jar
mybatis-spring-1.2.0.jar
mysql-connector-java-5.1.6.jar
servlet-api.jar
slf4j-api-1.7.7.jar
slf4j-jdk14-1.7.7.jar
slf4j-log4j12-1.7.2.jar
spring-aop-4.1.2.RELEASE.jar
spring-beans-4.1.2.RELEASE.jar
spring-context-4.1.2.RELEASE.jar
spring-core-4.1.2.RELEASE.jar
spring-expression-4.1.2.RELEASE.jar
spring-jdbc-4.1.2.RELEASE.jar
spring-test-4.1.2.RELEASE.jar
spring-tx-4.1.2.RELEASE.jar
spring-web-4.1.2.RELEASE.jar
spring-webmvc-4.1.2.RELEASE.jar
standard.jar
thumbnai.jar
mave导包
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<log4j.version>1.2.17</log4j.version>
<spring.version>4.3.9.RELEASE</spring.version>
<mybatis.version>3.2.2</mybatis.version>
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</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-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-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</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-oxm</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-tx</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-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- 上传下载 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.1</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
</dependencies>
spring配置
<!-- 引入mvc配置文件-->
<import resource="classpath:applicationContext-mvc.xml"/>
<!-- 扫描包 扫描service层 controller层-->
<context:component-scan base-package="cn.itsource"></context:component-scan>
<!-- 引入jdbc.properties-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- dataSource-->
<!-- 连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!--maxActive: 最大连接数量 -->
<property name="maxActive" value="150" />
<!--minIdle: 最小空闲连接 -->
<property name="minIdle" value="5" />
<!--maxIdle: 最大空闲连接 -->
<property name="maxIdle" value="20" />
<!--initialSize: 初始化连接 -->
<property name="initialSize" value="30" />
<!-- 连接被泄露时是否打印 -->
<property name="logAbandoned" value="true" />
<!--removeAbandoned: 是否自动回收超时连接 -->
<property name="removeAbandoned" value="true" />
<!--removeAbandonedTimeout: 超时时间(以秒数为单位) -->
<property name="removeAbandonedTimeout" value="10" />
<!--maxWait: 超时等待时间以毫秒为单位 1000等于60秒 -->
<property name="maxWait" value="1000" />
<!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. -->
<property name="timeBetweenEvictionRunsMillis" value="10000" />
<!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
<property name="numTestsPerEvictionRun" value="10" />
<!-- 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程 -->
<property name="minEvictableIdleTimeMillis" value="10000" />
<property name="validationQuery" value="SELECT NOW() FROM DUAL" />
</bean>
<!-- sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:cn/itsource/mapper/*Mapper.xml"></property>
</bean>
<!-- 扫描mapper-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itsource.mapper"/>
</bean>
<!-- 事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 2.开启注解事务:解析@Transactional注解 -->
<tx:annotation-driven transaction-manager="transactionManager" />
springMVC配置
<!-- 开启spring对springmvc 注解的支持 RequestMappeing -->
<mvc:annotation-driven />
<!-- 对静态资源如图片进行放行,不经过DispatcherServlet,使用tomcat的DefaultServlet处理 -->
<mvc:default-servlet-handler />
<!-- 视图解析器:设置视图路径的前后缀,该配置可以让我们写视图路径的时候更简单。 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- struts:<result name="login">/WEB-INF/views/login.jsp</result> -->
<!--前缀: jsp在当前工程文件夹的路径 -->
<property name="prefix" value="/WEB-INF/views/" />
<!--后缀:扩展名 -->
<property name="suffix" value=".jsp" />
</bean>
web.xml
<!-- 配置核心控制器 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 引用spring配置(包括springmvc+spring+mybatis)-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
当与spring集成以后就再也不需要我们自己管理SqlSessionFactory,也不用我们自己去实现dao
dao层接口
List<Product> queryAll();
service层
@Autowired
private ProductMapper productMapper;
@Override
public List<Product> queryAll() {
return productMapper.queryAll();
}
直接注入dao层,调用方法就行
Controller
@Autowired
private IProductService productService;
@RequestMapping("/product")
public String queryAll(){
productService.queryAll();
return null;
}
ssm集成完毕