目录
1.创建maven项目,在pom.xml文件中导入mybatis的 依赖
4.创建mybatis的全局配置文件mybatis-config.xml
2.4.2使用association联合查询定义对象的封装规则
1.使用where标签去掉sql中多余的and(只能去掉前面多余的)
2.1在MyBatis-config.xml中添加cacheEnable属性
一、创建一个简单的mybatis项目(Maven版本)
1.创建maven项目,在pom.xml文件中导入mybatis的 依赖
<dependencies>
<!--mybattis包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!--数据库连接包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
</dependencies>
2.在数据库中创建表
CREATE TABLE tbl_employee(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
last_name VARCHAR(50),
email VARCHAR(50),
gender CHAR(1)
);
3.创建对应的JavaBean对象和接口方法
public class Employee {
private Integer id ;
private String lastName;
private String email ;
private String gender ;
}
public interface EmployeeDao {
//按照员工id查询员工
public Employee getEmpById(Integer id);
}
4.创建mybatis的全局配置文件mybatis-config.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>
<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_0325"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<!--引用我们编写的每一个接口的实现文件-->
<mappers>
<mapper resource="employeeDao.xml"/>
</mappers>
</configuration>
5.创建sql映射文件employeeDao.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">
<!--namespace名称空间,写接口的全类名,相当于告诉MyBatis这个配置文件是实现哪个接口的-->
<mapper namespace="com.hzj.dao.EmployeeDao">
<!--id:写要实现的方法名-->
<!--#{属性名}:表示取出传递过来的某个参数的值-->
<select id="getEmpById" resultType="com.hzj.bean.Employee">
select * from t_employee where id = #{id}
</select>
</mapper>
6.编写测试方法
public class mybatisTest {
@Test
public void test() throws IOException {
//1.根据配置文件创建一个SqlSessionFactory对象
//SqlSessionFactory:是sqlSession工厂,负责创建SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
Employee empById = null;
//2.从sqlSessionFactory中获取和数据库的一次会话
SqlSession openSession = sqlSessionFactory.openSession();
try {
//3.使用sqlSession操作数据库,获取到dao接口的实现
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
empById = employeeDao.getEmpById(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
openSession.close();
}
System.out.println(empById);
}
}
二、mybatis实现增删改查
1.编写数据库实体类
public class Employee {
private Integer id;
private String empName;
private String email;
private Integer gender;
}
2.创建接口类
public interface employeeDao {
//根据id号查询员工
public Employee getEmpById(Integer id);
//员工修改
public int updateEmployee(Employee employee);
//根据id删除员工
public boolean deletEmployee(Integer id);
//添加员工
public int insertEmployee(Employee employee);
}
3.书写mybatis的全局配置文件和sql映射文件
mybatis-config.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>
<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_0325"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<!--引用我们编写的每一个接口的实现文件-->
<mappers>
<mapper resource="employeeDao.xml"/>
</mappers>
</configuration>
employeeDao.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">
<!--namespace名称空间,写接口的全类名,相当于告诉MyBatis这个配置文件是实现哪个接口的-->
<mapper namespace="com.hzj.dao.employeeDao">
<!--select表示表示查询
id:写要实现的方法名
#{属性名}:表示取出传递过来的某个参数的值
返回值类型为数据库实体类-->
<!--public Employee getEmpById(Integer id);-->
<select id="getEmpById" resultType="com.hzj.bean.Employee">
select * from t_employee where id = #{id}
</select>
<!--
增删改不用写返回值类型;增删改是返回影响多少行
mybatis会自动判断,
如果是数字(int,long),返回数字
如果是boolean(影响0行自动封装false)
-->
<!--public int updateEmployee(Employee employee);-->
<update id="updateEmployee">
update t_employee set empname=#{empName} , gender=#{gender} , email=#{email} where id=#{id}
</update>
<!--public boolean deletEmployee(Integer id);-->
<delete id="deletEmployee">
delete from t_employee where id=#{id}
</delete>
<!--public int insertEmployee(Employee employee);-->
<insert id="insertEmployee">
insert into t_employee(empname,gender,email) values(#{empName},#{gender},#{email})
</insert>
</mapper>
4.编写测试方法
public class MybatisCRUDTest {
//生成一个工厂类
SqlSessionFactory sqlSessionFactory;
//在方法执行之前运行
@Before
public void initSqlSessionFactory() throws IOException {
//1.根据配置文件创建一个SqlSessionFactory对象
//SqlSessionFactory:是sqlSession工厂,负责创建SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test() throws IOException {
//得到sqlsession对象,true代表自动提交
SqlSession openSession = sqlSessionFactory.openSession();
//获取到接口的实现
employeeDao employeeDao = openSession.getMapper(employeeDao.class);
try {
Employee empById = employeeDao.getEmpById(1);
System.out.println(empById);
} catch (Exception e) {
e.printStackTrace();
} finally {
openSession.close();
}
}
/*
* 增删改要提交事务两种方法
* 1.在得到sqlsession对象时设置自动提交
* SqlSession sqlSession =
sqlSessionFactory.openSession(true);
* 2.在调用方法之后,调用commit()手动提交
* */
@Test
public void InsertTest(){
//得到sqlsession对象,true代表自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
try {
employeeDao mapper = sqlSession.getMapper(employeeDao.class);
int i = mapper.insertEmployee(new Employee(null, "hzjx", "hzjx@zhj.com", 1));
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
} finally {
//增删改要提交事务
//sqlSession.commit();
sqlSession.close();
}
}
@Test
public void updateTest(){
SqlSession sqlSession = sqlSessionFactory.openSession(true);
try {
employeeDao employeeDao = sqlSession.getMapper(employeeDao.class);
int i = employeeDao.updateEmployee(new Employee(3, "huang", "hzj@zh", 1));
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
} finally {
//sqlSession.commit();
sqlSession.close();
}
}
三、mybatis的全局配置
mybatis中有两个重要的配置文件
1、全局配置文件:mybatis-config,xml;知道mybatis正确运行的全局设置
2、SQL映射文件:EmpoyeeDao.xml;对Dao接口方法的实现描述
细节:
1、SqlSession openSession = sqlSessionFactory.openSession();//获取到接口的实现
employeeDao employeeDao = openSession.getMapper(employeeDao.class);
//获取到的是接口的代理对象
2、SqlSessionFactory 和SqlSession
SqlSessionFactory创建SqlSession对象,Factory只new一次就好
SqlSession:相当于connection和数据库进行交互,和数据库的一次会话,每次都应该创建一个新的SqlSession;
1.mybatis全局配置中的属性设置
properties:可以引入外部文件
setting:可以改变mybatis的默认行为
typeAliases:可以为常用的javaBean起别名,在使用时就不用写全类名,写别名就可以获取对象
详细信息进 --> https://mybatis.org/mybatis-3/zh/getting-started.html
<?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>
<properties resource="jdbcConfig.properties"></properties>
<!--settings会改变MyBatis运行时行为-->
<settings>
<!--name配置项的key;value:配置项的值
mapUnderscoreToCamelCase 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
以下是满足驼峰命名时的行为
java:loginAccount 数据库:login_account
满足就可自动注入
-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--类型别名;为常用的类型(javaBean)起别名-->
<typeAliases>
<!--别名默认是类名(不区分大小写),配置文件中就可以不用写全类名直接写类名就好了-->
<!-- <typeAlias type="com.hzj.bean.Employee" alias="emp"></typeAlias>-->
<!--批量起别名,默认别名都是类名-->
<!--<package name="com.hzj.bean"/>-->
<!--最后还是推荐使用全类名-->
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--引用我们编写的每一个接口的实现文件-->
<!--
url:从磁盘或者网络路径引用
resource:在类路径下找sql的映射文件
class:直接引用接口的全类名
需要将xml放在接口的同一路径下,文件名跟接口名相同
-->
<mappers>
<mapper resource="employeeDao.xml"/>
</mappers>
</configuration>
2.sql映射文件的属性设置
2.1 insert操作的参数设置
获取插入刚刚插入数据库的数据id
1、数据库支持id自增
设置userGeneratedKeys="true"和keyProperty="属性名";
2、数据不支持id自增
先从数据中查询最大的id+1,再赋值给employee的id属性
<!--让MyBatis自动的将自增的id赋值给传入的employee对象的id属性
userGeneratedKeys="true":原生jdbc获取自增主键的方法
keyProperty="";将刚才自增的id封装给哪个属性
-->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
insert into t_employee(empname,gender,email) values(#{empName},#{gender},#{email})
</insert>
<!--数据库不支持id自增时获取id
先从数据库中查询最大的id+1,把它赋值给employee的id属性
-->
<insert id="insertEmployee2" >
/*查询主键,order表示运行顺序
order="BEFORE"
在核心sql语句运行之前查询id,将查到的id赋值给JavaBean中的某个属性,
注意写入返回值类型resultType="integer"*/
<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>
测试方法
@Test
public void test02() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession(true);
try {
employeeDao mapper = sqlSession.getMapper(employeeDao.class);
Employee employee = new Employee(null, "hzjx", "hzjx@zhj.com", 1);
int i = mapper.insertEmployee(employee);
System.out.println(i);
System.out.println("刚才插入的id:"+employee.getId());
System.out.println(employee);
} catch (Exception e) {
e.printStackTrace();
} finally {
//增删改要提交事务
//sqlSession.commit();
sqlSession.close();
}
}
/*数据库不支持自增id时,获取id属性*/
@Test
public void test03() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession(true);
try {
employeeDao mapper = sqlSession.getMapper(employeeDao.class);
Employee employee = new Employee(null, "hzjx", "hzjx@zhj.com", 1);
int i = mapper.insertEmployee2(employee);
System.out.println(i);
System.out.println("刚才插入的id:"+employee.getId());
System.out.println(employee);
} catch (Exception e) {
e.printStackTrace();
} finally {
//增删改要提交事务
//sqlSession.commit();
sqlSession.close();
}
}
2.2select查询的参数设置
传入参数的方法
1、单个参数
基本类型:
取值:#{xx}
2、多个参数
取值:不能使用#{参数名}(无效)
可用的取值方式:0,1(参数的索引)或者param1,param2(第几个参数paramN)
原因:只要传入多个参数:Mybatis会自动将这些参数封装在一个map中,封装时使用的key就是参数的索引或者参数的第几个标识
<select id="getEmpById2" resultType="com.hzj.bean.Employee">
select * from t_employee where id = #{0} and empname=#{1}
</select>
我们可以使用在参数上使用Param:为参数指定key,这样map封装参数时,就会使用我们指定的key
public Employee getEmpById2(@Param("id") Integer id, @Param("empname") String name);
<select id="getEmpById2" resultType="com.hzj.bean.Employee">
select * from t_employee where id = #{id} and empname=#{empname}
</select>
3、传入map
取值:#{key}
4、传入了pojo对象
取值:#{pojo的属性名}
<!—
select表示查询
id:写要实现的方法名
#{属性名}:表示取出传递过来的某个参数的值-->
<!--public Employee getEmpById(Integer id);-->
<select id="getEmpById" resultType="com.hzj.bean.Employee">
select * from t_employee where id = #{id}
</select>
<!--传入多个参数-->
<!--public Employee getEmpById2(Integer id,String name);-->
<select id="getEmpById2" resultType="com.hzj.bean.Employee">
select * from t_employee where id = #{id} and empname=#{empname}
</select>
<!--传入map-->
<!--public Employee getEmpByMap(Map<String,Object> map);-->
<select id="getEmpByMap" resultType="com.hzj.bean.Employee">
select * from t_employee where id = #{id} and empname=#{empname}
</select>
@Test
public void testSelect() throws IOException {
//得到sqlsession对象,true代表自动提交
SqlSession openSession = sqlSessionFactory.openSession();
//获取到接口的实现
employeeDao employeeDao = openSession.getMapper(employeeDao.class);
try {
//多个参数
Employee empById = employeeDao.getEmpById2(1,"admin");
System.out.println(empById);
//map参数
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("empname", "admin");
Employee empByMap = employeeDao.getEmpByMap(map);
System.out.println("empByMap-->"+empByMap);
} catch (Exception e) {
e.printStackTrace();
} finally {
openSession.close();
}
}
2.2.1返回值为list集合
1、设置<select>的返回值类型为集合中的元素类型
mybatis会自动把数据封装成list返回
<!--
//查询所有员工
public List<Employee> getAllEmps();
如果返回值是集合,写的是集合里面元素的类型
-->
<select id="getAllEmps" resultType="com.hzj.bean.Employee">
select * from t_employee
</select>
测试方法
SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlSessionFactory() throws IOException {
//1.根据配置文件创建一个SqlSessionFactory对象
//SqlSessionFactory:是sqlSession工厂,负责创建SqlSessionFactory对象
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testSelectAll() throws IOException {
//得到sqlsession对象,true代表自动提交
SqlSession openSession = sqlSessionFactory.openSession();
//获取到接口的实现
employeeDao employeeDao = openSession.getMapper(employeeDao.class);
try {
List<Employee> allEmps = employeeDao.getAllEmps();
for (Employee employee:allEmps) {
System.out.println(employee);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
openSession.close();
}
运行结果
Employee{id=1, empName='admin', email='hzj@hzj', gender=1}
Employee{id=5, empName='hzjx', email='hzjx@zhj.com', gender=1}
Employee{id=6, empName='hzjx', email='hzjx@zhj.com', gender=1}
Employee{id=7, empName='hzjx', email='hzjx@zhj.com', gender=1}
Employee{id=8, empName='hzjx', email='hzjx@zhj.com', gender=1}
Employee{id=9, empName='hzjx', email='hzjx@zhj.com', gender=1}
Employee{id=10, empName='hzjx', email='hzjx@zhj.com', gender=1}
2.2.2 返回值为map集合
1、返回值为一个map直接设置resultType="map"
2、返回值为多个map
字段中的主键做为map中的key,value是这个记录封装的对象
在接口方法中加上@MapKey("id")注解,将id做为map的key
返回值类型写对应的元素类型
<!-- //返回一个mao
public Map<String,Object> getEmpByIdReturnMap(Integer id);
-->
<select id="getEmpByIdReturnMap" resultType="map">
select * from t_employee where id = #{id}
</select>
<!--
//返回所有员工封装在map中
//字段中的主键做为key,value是这条记录封装号的对象
//将id做为key
@MapKey("id")
public Map<Integer,Employee> getAllEmpsReturnMap();
返回多个map集合时,返回值类型写元素类型
-->
<select id="getAllEmpsReturnMap" resultType="com.hzj.bean.Employee">
select * from t_employee
</select>
@Test
public void testSelectReturnMap() throws IOException {
SqlSession openSession = sqlSessionFactory.openSession();
//获取到接口的实现
employeeDao employeeDao = openSession.getMapper(employeeDao.class);
try {
//查询单条记录,封装map
Map<String, Object> map = employeeDao.getEmpByIdReturnMap(1);
System.out.println(map);
//查询返回多个map
Map<Integer, Employee> allEmpsReturnMap = employeeDao.getAllEmpsReturnMap();
System.out.println(allEmpsReturnMap);
} catch (Exception e) {
e.printStackTrace();
} finally {
openSession.close();
}
}
运行结果
{empname=admin, gender=1, id=1, login_account=a, email=hzj@hzj}
{1=Employee{id=1, empName='admin', email='hzj@hzj', gender=1},
5=Employee{id=5, empName='hzjx', email='hzjx@zhj.com', gender=1},
6=Employee{id=6, empName='hzjx', email='hzjx@zhj.com', gender=1},
7=Employee{id=7, empName='hzjx', email='hzjx@zhj.com', gender=1},
8=Employee{id=8, empName='hzjx', email='hzjx@zhj.com', gender=1},
9=Employee{id=9, empName='hzjx', email='hzjx@zhj.com', gender=1},
10=Employee{id=10, empName='hzjx', email='hzjx@zhj.com', gender=1}}
2.3自定义封装规则
当数据库列名于实体属性名不一一对应时
1、数据库满足驼峰命名规则,开启驼峰命名法
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
2、在写sql语句时,给对应的列名起别名
3、使用自定义规则
<mapper namespace="com.hzj.dao.CatDao"> <!--public Cat getCatById(Integer id); resultMap="myCat"指定查出数据封装结果时,使用自定义规则 --> <select id="getCatById" resultMap="myCat"> select * from t_employee where id = #{cid} </select> <!--自定义封装规则--> <resultMap id="myCat" type="com.hzj.bean.Cat"> <!--指定主键列的对应规则 column="id",指定哪一列是主键列 property="",指定cat哪个属性封装id这一列数据 --> <id column="id" property="id"></id> <!--普通列--> <result property="cempName" column="empname"></result> <result property="cemail" column="email"></result> <result property="cgender" column="gender"></result> </resultMap> </mapper>
@Test public void testCat(){ SqlSession openSession = sqlSessionFactory.openSession(); CatDao catDao = openSession.getMapper(CatDao.class); Cat catById = catDao.getCatById(1); System.out.println(catById); openSession.close(); }
2.4联合查询
2.4.1使用级联方式封装对象
public class Department {
private Integer id ;
private String departmentName ;
// 省略 get/set方法
}
public class Employee {
private Integer id ;
private String lastName;
private String email ;
private String gender ;
private Department dept ;
// 省略 get/set 方法
}
使用级联方式赋值
<select id="getEmployeeAndDept" resultMap="myEmpAndDept" >
SELECT e.id eid, e.last_name, e.email,e.gender ,d.id did, d.dept_name FROM
tbl_employee e , tbl_dept d WHERE e.d_id = d.id AND e.id = #{id}
</select>
<resultMap type="com.atguigu.mybatis.beans.Employee" id="myEmpAndDept">
<id column="eid" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!-- 级联的方式 -->
<result column="did" property="dept.id"/>
<result column="dept_name" property="dept.departmentName"/>
</resultMap>
2.4.2使用association联合查询定义对象的封装规则
<select id="getEmployeeAndDept" resultMap="myEmpAndDept" >
SELECT e.id eid, e.last_name, e.email,e.gender ,d.id did, d.dept_name FROM
tbl_employee e , tbl_dept d WHERE e.d_id = d.id AND e.id = #{id}
</select>
<resultMap type="com.atguigu.mybatis.beans.Employee" id="myEmpAndDept">
<id column="eid" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!--联合查询-->
<association property="dept" javaType="com.atguigu.mybatis.beans.Department">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
</association>
</resultMap>
2.5分步查询
实际的开发中,对于每个实体类都应该有具体的增删改查方法,也就是 DAO 层, 因此
对于查询员工信息并且将对应的部门信息也查询出来的需求,就可以通过分步的方式
完成查询。
1 、先通过员工的 id 查询员工信息
2、 再通过查询出来的员工信息中的外键(部门 id)查询对应的部门信息.
<select id="getEmployeeAndDeptStep" resultMap="myEmpAndDeptStep">
select id, last_name, email,gender,d_id from tbl_employee where id =#{id}
</select>
<resultMap type="com.atguigu.mybatis.beans.Employee" id="myEmpAndDeptStep">
<id column="id" property="id" />
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!--使用association调用另一个查询方法实现联合查询
fetchType="lazy"表示延迟加载-->
<association property="dept"
select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
column="d_id" fetchType="lazy"></association>
</resultMap>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
四、动态SQL
public class Teacher {
private Integer id;
private String name;
private String course;
private String address;
private Date birth;}
1.使用where标签去掉sql中多余的and(只能去掉前面多余的)
<select id="getTeacherByCondition" resultMap="teacherMap">
select * from t_teacher
<!--where标签可以去掉前面多余的and-->
<where>
<!--if:传入非常强大的判断条件,OGNL表达式
test=""编写判断条件
id!=null;取出传入的JavaBean属性中的id值,判断是否为空
空串‘’
and,or-->
<if test="id!=null">
id > #{id}
</if>
<if test="name!=null and name!=''">
and teacherName like #{name }
</if>
<if test="birth!=null">
and birth_date < #{birth}
</if>
</where>
</select>
2.使用trim去掉多余的and
<select id="getTeacherByCondition" resultMap="teacherMap">
select * from t_teacher
<!--trim()截取字符串
prefix="where" ;为下面的sql语句添加一个前缀
prefixOverrides="" ;取出整体字符串前面多余的字符
suffix="" ;为整体添加后缀
suffixOverrides="";后面哪个多了可以去掉
-->
<trim prefix="where"
prefixOverrides="and"
suffixOverrides="and">
<!--if:传入非常强大的判断条件,OGNL表达式
test=""编写判断条件
id!=null;取出传入的JavaBean属性中的id值,判断是否为空
空串‘’
and,or-->
<if test="id!=null">
id > #{id}
</if>
<if test="name!=null and name!=''">
and teacherName like #{name }
</if>
<!--遇到特殊符号要使用转义字符-->
<if test="birth!=null">
and birth_date < #{birth}
</if>
</trim>
</select>
@Test
public void test() throws IOException {
SqlSession openSession = sqlSessionFactory.openSession();
try {
TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);
Teacher teacher2 = new Teacher();
teacher2.setId(1);
teacher2.setName("%m%");
teacher2.setBirth(new Date());
List<Teacher> teacherList = tearcherDao.getTeacherByCondition(teacher2);
System.out.println(teacherList);
}finally {
openSession.close();
}
}
3.使用foreach遍历添加元素
<!--输出list集合存在的id号对应的数据
public List<Teacher> getTeacherByIdIn(@Param("ids") List<Integer> ids);-->
<select id="getTeacherByIdIn" resultMap="teacherMap">
select * from t_teacher where id in
<!--foreach遍历集合
collection:指定要遍历的集合
item:为每次遍历出的元素起一个变量名
open:指定以什么开头
close:指定以什么结尾
separator:为每一个遍历的元素添加分隔符
-->
<foreach collection="ids"
item="id_item"
open="("
close=")"
separator=",">
#{id_item}
</foreach>
</select>
@Test
public void test() throws IOException {
SqlSession openSession = sqlSessionFactory.openSession();
try {
TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);
List<Teacher> list = tearcherDao.getTeacherByIdIn(Arrays.asList(1, 2, 3, 4));
System.out.println(list);
}finally {
openSession.close();
}
}
4.使用choose进行动态sql拼接
<!--public List<Teacher> getTeacherByIdChoose(Teacher teacher);-->
<select id="getTeacherByIdChoose" resultMap="teacherMap">
select * from t_teacher
<where>
<!--若id中有值,就按id号查询
若id中没值,name中有值再按name查询
若name没值,birth有值就按birth查询
若都没值,则查询所有数据-->
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="name!=null and name!=''">
teacherName=#{name}
</when>
<when test="birth!=null">
birth_date=#{birth}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
@Test
public void test() throws IOException {
SqlSession openSession = sqlSessionFactory.openSession();
try {
TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);
Teacher teacher2 = new Teacher();
teacher2.setId(1);
teacher2.setName("lucy");
List<Teacher> teacherByIdChoose = tearcherDao.getTeacherByIdChoose(teacher2);
System.out.println(teacherByIdChoose);
}finally {
openSession.close();
}
}
运行结果
[teacher{id=3, name='lucy', course='英语', address='罗湖区', birth=Thu Jul 12 00:00:00 CST 2018}]
5.使用set进行非全字段更新
<!--根据传入对象的值,更新数据库中的数据
public int updateTeacher(Teacher teacher);-->
<update id="updateTeacher" >
update t_teacher
<!--只更新有传入值的数据-->
<set>
<if test="name!=null and !name.equals("")">
teacherName=#{name}
</if>
<if test="course!=null and !course.equals("")">
class_name=#{course}
</if>
<if test="address!=null and !address.equals("")">
address=#{address}
</if>
<if test="birth!=null and !birth.equals("")">
birth_date=#{birth}
</if>
<where>
id=#{id}
</where>
</set>
</update>
@Test
public void test02() throws IOException {
SqlSession openSession = sqlSessionFactory.openSession();
try {
TearcherDao tearcherDao = openSession.getMapper(TearcherDao.class);
Teacher teacher2 = new Teacher();
teacher2.setId(1);
teacher2.setName("hzjAdmin");
int i = tearcherDao.updateTeacher(teacher2);
System.out.println(i);
}finally {
openSession.commit();
openSession.close();
}
}
6.bind的作用
/*绑定一个表达式的值给一个变量*/
<bind name="_name" value="'%'+name+'%'"></bind>
<if test="name!=null and name!=''">
and teacherName like #{_name }
</if>
7.使用include抽取重用的sql语句
<!-- 抽取可重用的sql语句-->
<sql id="selectSql">select * from t_teacher</sql>
<!-- public Teacher getTeacherById(Integer id);-->
<select id="getTeacherById" resultMap="teacherMap">
<!--引用抽取的sql-->
<include refid="selectSql"></include>
where id=#{id}
</select>
五、缓存
1.一级缓存
一级缓存是sqlSession级别的缓存
1、不同的sqlSession使用不同的一级缓存,只有在同一个sqlSession期间查询到的数据才会保存到这个sqlSession的缓存中,下次使用这个sqlSession才能拿到缓存的数据
2、同一个方法,不同的参数,没查询过没保存
3、在sqlSession期间执行增删改操作,会清空一级缓存
4、手动清空缓存
openSession.clearCache();
5、每次查询先看一级缓存中有没有,没有再去查询数据库
2.二级缓存
一级缓存sqlSession提交或者关闭后,一级缓存中的数据才会存到二级缓存中,二级缓存是namespace级别的缓存
二级缓存需要手动开启
2.1在MyBatis-config.xml中添加cacheEnable属性
<!--开启二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2.2在sql映射文件中加上cache标签
<mapper namespace="com.hzj.dao.TeacherDao.xml">
<!--使用二级缓存-->
<cache></cache>
</mapper>
2.3对应的实体类要实现序列化接口
public class Teacher implements Serializable
2.4二级缓存的相关属性
1 eviction=“FIFO”:缓存回收策略:
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
2 flushInterval:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
3 size:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
4 readOnly:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
3.查询缓存的顺序
1.不会出现一级缓存和二级缓存中有同一个数据的情况
1、一级缓存中的数据连接关闭后才传给二级缓存
2、若二级缓存没有想要的数据,才会看一级缓存,一级缓存没有再去查数据库,数据库的查询结果放在一级缓存中
2.任何时候都是先看二级缓存、再看一级缓存,都没有才去查数据库
顺序 :二 --> 一 –-> 数据库
4.整合第三方缓存
1) 为了提高扩展性。MyBatis 定义了缓存接口 Cache。我们可以通过实现 Cache 接口来定义二级缓存
2) EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider
4.1整合EhCahe的步骤
4.1.1导入ehcache的包以及整合类和日志包
ehcache-core-2.6.8.jar
mybatis-ehcache-1.0.3.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.2.jar
4.1.2编写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:\atguigu\ehcache" />
<defaultCache
maxElementsInMemory="1000" 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 标签
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>