一、映射Mapper
接口方法映射到对应的SQL
XXXMapper.xml的命名空间名称就是Mapper接口的全限定名
Mapper接口上也可以通过相应的注释来写SQL(但是最好不要这么写哦)
// 查询全部
// @Select("select * from employee")
List<Employee> findAll();
employeeMapper.xml
<?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="cn.cxm.mapper.mapper.EmployeeMapper">
<select id="findOne" parameterType="long" resultType="cn.cxm.mapper.domain.Employee">
SELECT * FROM employee WHERE id=#{id}
</select>
<select id="findAll" parameterType="long" resultType="cn.cxm.mapper.domain.Employee">
SELECT * FROM employee
</select>
<insert id="save" parameterType="cn.cxm.mapper.domain.Employee" >
INSERT INTO employee (name,age) VALUES (#{name},#{age})
</insert>
<!--
<update id="update" parameterType="cn.cxm.mapper.domain.Employee">
UPDATE employee SET name=#{name},age=#{age} WHERE id=#{id}
</update>
-->
<delete id="delete" parameterType="long">
DELETE FROM employee WHERE id=#{id}
</delete>
<!--
添加多条数据
使用foreach标签,collection:遍历的集合,item:集合的每一个元素
separator:分离符
-->
<insert id="batchSave" parameterType="list">
INSERT INTO employee (name,age) VALUES
<foreach collection="list" item="emp" separator=",">
(#{emp.name},#{emp.age})
</foreach>
</insert>
<!--批量删除,删除一定范围,使用in( ,)-->
<delete id="batchDelete" parameterType="list">
DELETE FROM employee WHERE id in
<foreach collection="list" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<!--模糊查询-->
<!--
<select id="queryAll" parameterType="list" resultType="cn.cxm.mapper.domain.Employee">
SELECT * FROM employee where name LIKE CONCAT("%",#{name},"%")
</select>
-->
<!--使用where标签,自动将第一个and替换为where-->
<!--多条件查询-->
<select id="queryAll" parameterType="cn.cxm.mapper.query.EmployeeQuery" resultType="cn.cxm.mapper.domain.Employee">
SELECT * FROM employee
<where>
<if test="name!=null and name!=''">
AND name LIKE CONCAT("%",#{name},"%")
</if>
<if test="minAge!=null">
AND age>=#{minAge}
</if>
<if test="maxAge!=null">
AND <![CDATA[ age<=#{maxAge}]]>
</if>
</where>
</select>
<!--查询总条数-->
<select id="count" parameterType="cn.cxm.mapper.query.EmployeeQuery" resultType="long">
SELECT count(id) FROM employee
<where>
<if test="name!=null and name!=''">
AND name LIKE CONCAT("%",#{name},"%")
</if>
<if test="minAge!=null">
AND age>=#{minAge}
</if>
<if test="maxAge!=null">
AND <![CDATA[ age<=#{maxAge}]]>
</if>
</where>
</select>
<!--动态修改,当使用动态修改,只修改其中的一条数据,同一id的其他数据不会改变-->
<update id="update" parameterType="cn.cxm.mapper.domain.Employee">
UPDATE employee
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="age!=null">
age=#{age},
</if>
</set>
WHERE id=#{id}
</update>
</mapper>
EmployeeMapper
package cn.cxm.mapper.mapper;
import cn.cxm.mapper.domain.Employee;
import cn.cxm.mapper.query.EmployeeQuery;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface EmployeeMapper {
// 添加
void save(Employee employee);
// 删除
void delete(Long id);
// 修改
void update(Employee employee);
// 查询一条
Employee findOne(Long id);
// 查询全部
// @Select("select * from employee")
List<Employee> findAll();
// 批量添加
void batchSave(List<Employee> employee);
// 批量删除
void batchDelete(List<Long> id);
// 高级查询之模糊查询
// List<Employee> queryAll(String name);
// 高级查询之多条件查询
List<Employee> queryAll(EmployeeQuery query);
// 查询总条数
Long count(EmployeeQuery query);
}
调用 Mapper的方法
@Test
public void save() throws Exception{
SqlSession session = MybatisUtil.getSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
Employee employee = new Employee();
employee.setName("大蛇丸");
employee.setAge(123);
mapper.save(employee);
session.commit();
}
二.高级查询
准备一个Query对象(封装所有条件)
模糊查询 concat("%",#{name},"%")
遇到特殊符号 1.转义 < 2.CDATA段 <![CDATA[...]]>
使用where标签(第一个and变成where)
if中有多个条件使用 and/or 进行关联
如果出现相就的代码,可以单独抽取sql标签,引用include即可
.employeeMapper.xml
<!--模糊查询-->
<!--
<select id="queryAll" parameterType="list" resultType="cn.cxm.mapper.domain.Employee">
SELECT * FROM employee where name LIKE CONCAT("%",#{name},"%")
</select>
-->
<!--使用where标签,自动将第一个and替换为where-->
<!--多条件查询-->
<select id="queryAll" parameterType="cn.cxm.mapper.query.EmployeeQuery" resultType="cn.cxm.mapper.domain.Employee">
SELECT * FROM employee
<where>
<if test="name!=null and name!=''">
AND name LIKE CONCAT("%",#{name},"%")
</if>
<if test="minAge!=null">
AND age>=#{minAge}
</if>
<if test="maxAge!=null">
AND <![CDATA[ age<=#{maxAge}]]>
</if>
</where>
</select>
<!--查询总条数-->
<select id="count" parameterType="cn.cxm.mapper.query.EmployeeQuery" resultType="long">
SELECT count(id) FROM employee
<where>
<if test="name!=null and name!=''">
AND name LIKE CONCAT("%",#{name},"%")
</if>
<if test="minAge!=null">
AND age>=#{minAge}
</if>
<if test="maxAge!=null">
AND <![CDATA[ age<=#{maxAge}]]>
</if>
</where>
</select>
代码片段
<select id="findByQuery" parameterType="employeeQuery" resultType="employee">
select * from employee <include refid="whereSql" />
</select>
<!--准备代码片断-->
<sql id="whereSql">
<where>
<if test="name!=null and name!=''">
and name like concat("%",#{name},"%")
</if>
<if test="minAge!=null">
and age >= #{minAge}
</if>
<if test="maxAge!=null">
<![CDATA[ and age<=#{maxAge} ]]>
</if>
</where>
</sql>
批量删除,添加,动态修改
首先知道sql delete from 表名 where id in (?,?,…)
collection="":代表你要循环的是什么? array/list
如果传过来的是数据,写array(集合就写list)
item:循环的每一个数据
open:拼接字符串以什么开始
close:拼接字符串以什么结尾
separator:拼接的时候每个值使用,隔开
index:遍历的下标
动态修改
<!--动态修改,当使用动态修改,只修改其中的一条数据,同一id的其他数据不会改变-->
<update id="update" parameterType="cn.cxm.mapper.domain.Employee">
UPDATE employee
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="age!=null">
age=#{age},
</if>
</set>
WHERE id=#{id}
</update>
批量删除
<!--批量删除,删除一定范围,使用in( ,)-->
<delete id="batchDelete" parameterType="list">
DELETE FROM employee WHERE id in
<foreach collection="list" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
批量添加
<!--
添加多条数据
使用foreach标签,collection:遍历的集合,item:集合的每一个元素
separator:分离符
-->
<insert id="batchSave" parameterType="list">
INSERT INTO employee (name,age) VALUES
<foreach collection="list" item="emp" separator=",">
(#{emp.name},#{emp.age})
</foreach>
</insert>
多对一
准备两张表product、productdir,两个domain,两个mapper.xml
查询(嵌套结果:一条SQL,嵌套查询:多条SQL)
准备domain
product
private Long id;
private String name;
// private Long dirId;
private Double salePrice;
private String supplier;
private String brand;
private Double cutoff;
private Double costPrice;
private Productdir productdir;
//... getter,setter与toString
productdir
private Long id;
private String name;
//... getter,setter与toString
嵌套结果
查询的sql要关连多张表(一定要取别名,不然有些名称会产生冲突)
当我们使用了association 后默认的映射失败,需要自己手动完成映射
<?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="cn.cxm.many2one.mapper.ProductMapper">
<!--手动完成映射,id为我们取的名字,type为我们映射的类型-->
<resultMap id="ProductMap" type="cn.cxm.many2one.domain.Product">
<id property="id" column="id"/>
<result property="name" column="productName"/>
<result property="salePrice" column="salePrice"/>
<result property="supplier" column="supplier"/>
<result property="brand" column="brand"/>
<result property="cutoff" column="cutoff"/>
<result property="costPrice" column="costPrice"/>
<!--association:不管是多对一还是一对多都使用它,代表要关联一个对象,当你使用这个标签的时候,
自动映射就会失效,property="productdir" :属性名称,javaType=":属性的类型-->
<association property="productdir" javaType="cn.cxm.many2one.domain.Productdir">
<id property="id" column="did"/>
<result property="name" column="dname"/>
</association>
</resultMap>
<!--嵌套结果-->
<!--如果有字段名或者类型对应不上,这个时候我们需要手动映射
当在查询中出现相同到的名称的字段的时候,为了区分,我们这个时候就要为它取别名-->
<select id="findAll" resultMap="ProductMap">
SELECT p.*,d.id did,d.name dname FROM product p
JOIN productdir d on d.id=p.dir_id
</select>
</mapper>
嵌套查询
会产生n+1条sql
需要去找到对应的那条sql并且执行
保证MyBatis能找到这两个xml
ProductdirMapper.xml
<?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="cn.cxm.many2one.mapper.ProductdirMapper">
<select id="findOne" parameterType="long" resultType="cn.cxm.many2one.domain.Productdir">
SELECT* FROM productdir WHERE id=#{id}
</select>
</mapper>
Product.xml
<?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="cn.cxm.many2one.mapper.ProductMapper">
<resultMap id="ProductMap" type="cn.cxm.many2one.domain.Product">
<id property="id" column="id"/>
<result property="name" column="productName"/>
<result property="salePrice" column="salePrice"/>
<result property="supplier" column="supplier"/>
<result property="brand" column="brand"/>
<result property="cutoff" column="cutoff"/>
<result property="costPrice" column="costPrice"/>
<association property="productdir" javaType="cn.cxm.many2one.domain.Productdir"
column="dir_id" select="cn.cxm.many2one.mapper.ProductdirMapper.findOne"
>
</association>
</resultMap>
<!--嵌套查询-->
<select id="findAll" resultMap="ProductMap">
SELECT * FROM product p
</select>
</mapper>
一对多
Product
private Long id;
private String name;
// private Long dirId;
private Double salePrice;
private String supplier;
private String brand;
private Double cutoff;
private Double costPrice;
Productdir
private Long id;
private String name;
private List<Product> product=new ArrayList<>();
嵌套结果
<?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="cn.cxm.one2many.mapper.ProductdirMapper">
<!--手动完成映射,id为我们取的名字,type为我们映射的类型-->
<resultMap id="ProductdirMap" type="cn.cxm.one2many.domain.Productdir">
<id property="id" column="did"/>
<result property="name" column="dname"/>
<!--association:不管是多对一还是一对多都使用它,代表要关联一个对象,当你使用这个标签的时候,
自动映射就会失效,property="productdir" :属性名称,javaType=":属性的类型-->
<collection property="product" ofType="cn.cxm.one2many.domain.Product">
<id property="id" column="pid"/>
<result property="name" column="pname"/>
<result property="salePrice" column="psalePrice"/>
<result property="supplier" column="psupplier"/>
<result property="brand" column="pbrand"/>
<result property="cutoff" column="pcutoff"/>
<result property="costPrice" column="pcostPrice"/>
</collection>
</resultMap>
<!--嵌套结果-->
<!--如果有字段名或者类型对应不上,这个时候我们需要手动映射
当在查询中出现相同到的名称的字段的时候,为了区分,我们这个时候就要为它取别名-->
<select id="findAll" resultMap="ProductdirMap">
SELECT d.id did,d.name dname,p.id pid,p.ProductName pname,p.salePrice psalePrice,
p.supplier psupplier,p.brand pbrand ,p.cutoff pcutoff,p.costPrice pcostPrice FROM productdir d
LEFT JOIN product p on d.id=p.dir_id
</select>
</mapper>
嵌套查询
productMapper
<?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="cn.cxm.one2many.mapper.ProductMapper">
<select id="findBydeptId" parameterType="long" resultType="cn.cxm.one2many.domain.Product">
SELECT * FROM product WHERE dir_id=#{id}
</select>
</mapper>
productdirMapper
<?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="cn.cxm.one2many.mapper.ProductdirMapper">
<!--手动完成映射,id为我们取的名字,type为我们映射的类型-->
<resultMap id="ProductdirMap" type="cn.cxm.one2many.domain.Productdir">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!--association:不管是多对一还是一对多都使用它,代表要关联一个对象,当你使用这个标签的时候,
自动映射就会失效,property="productdir" :属性名称,javaType=":属性的类型-->
<collection property="product" ofType="cn.cxm.one2many.domain.Product"
column="id" select="cn.cxm.one2many.mapper.ProductMapper.findBydeptId">
</collection>
</resultMap>
<!--嵌套结果-->
<!--如果有字段名或者类型对应不上,这个时候我们需要手动映射
当在查询中出现相同到的名称的字段的时候,为了区分,我们这个时候就要为它取别名-->
<select id="findAll" resultMap="ProductdirMap">
SELECT * FROM productdir p
</select>
</mapper>
嵌套查询
productMapper
<?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="cn.cxm.one2many.mapper.ProductMapper">
<select id="findBydeptId" parameterType="long" resultType="cn.cxm.one2many.domain.Product">
SELECT * FROM product WHERE dir_id=#{id}
</select>
</mapper>
productdirMapper
<?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="cn.cxm.one2many.mapper.ProductdirMapper">
<!--手动完成映射,id为我们取的名字,type为我们映射的类型-->
<resultMap id="ProductdirMap" type="cn.cxm.one2many.domain.Productdir">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!--association:不管是多对一还是一对多都使用它,代表要关联一个对象,当你使用这个标签的时候,
自动映射就会失效,property="productdir" :属性名称,javaType=":属性的类型-->
<collection property="product" ofType="cn.cxm.one2many.domain.Product"
column="id" select="cn.cxm.one2many.mapper.ProductMapper.findBydeptId">
</collection>
</resultMap>
<!--嵌套结果-->
<!--如果有字段名或者类型对应不上,这个时候我们需要手动映射
当在查询中出现相同到的名称的字段的时候,为了区分,我们这个时候就要为它取别名-->
<select id="findAll" resultMap="ProductdirMap">
SELECT * FROM productdir p
</select>
</mapper>
缓存
自带一级级联
二级缓存需要加上标签 <cache />
二级缓存的对象必需是序列化对象 .. implements Serializable
Mybatis集成SSM
新建一个javaweb项目
导入相关的包
配置applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
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.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--
需要配置的数据,配置的步骤:
创建db.properties -> 引入db.properties->创建数据源(dataSource)
-> 配置一个Bean:SqlSessionFactory ->配置mapper(接口,xml)->创建domain,mapper,查询测试
->完成service:扫描service层->完成controller,集成SpringMVC
Spring集成MyBatis (MyBatis操作数据库的对象交给Spring管理)
1.需要把SqlSessionFactory让Spring来管理
2.数据源(四大金刚) 3.别名的问题 4.可以找到mapper.xml
-->
<!--扫描service层-->
<context:component-scan base-package="cn.cxm.ssm.service" />
<!--引入外部的db.properties-->
<context:property-placeholder location="classpath:jdbc.properties" />
<!--配置dbcp连接池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!--
还记得以前JPA是怎么搞的? EntityManagerFactoryBean
猜:MyBatis:是否有一个SqlSessionFactoryBean的对象
-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource" />
<!--配置别名-->
<property name="typeAliasesPackage" value="cn.cxm.ssm.domain" />
<!--扫描 mapper.xml-->
<property name="mapperLocations" value="classpath:cn/cxm/ssm/mapper/*.xml" />
</bean>
<!--
<!–配置对应的MapperBean:只能配置一个Mapper,太多的话就很麻烦–>
<bean id="employeeMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sessionFactory" />
<property name="mapperInterface" value="cn.cxm.ssm.mapper.EmployeeMapper" />
</bean>
-->
<!--一劳永逸的配置Mapper的方案-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--扫描的包的配置,直接扫描包,以后里面的mapper就都可以使用-->
<property name="basePackage" value="cn.cxm.ssm.mapper" />
<property name="sqlSessionFactoryBeanName" value="sessionFactory" />
</bean>
<!--配置一个事务对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--事务的注解支持-->
<!-- 如果一定要修改上面的bean的id,那么下面的这里也需要相呼应,相同
<tx:annotation-driven transaction-manager="transactionManager" />-->
<tx:annotation-driven />
</beans>
配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--启动Spring的配置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--启动SpringMVC的配置-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
配置applicationContext-mvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<context:component-scan base-package=“cn.cxm.ssm.controller” />
<mvc:default-servlet-handler />
<mvc:annotation-driven />
<!--
如果我们是在SpringMVC中来引入Spring的xml,那么普通的集成运行没有问题
但是到后期和其它的一些框架集成就无法成功(比如说shiro),所以我们不提倡使用这种方式
-->
<!--<import resource="classpath:applicationContext.xml" />-->
<!--文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为1MB -->
<property name="maxUploadSize">
<value>1048576</value>
</property>
</bean>
service层里面注入的是XXXMapper
@Autowired
private EmployeeMapper employeeMapper;