知识点一.使用注解方式配置映射
CRUD
注意
1.results中的每个result需要用逗号分隔
2.查询所有的时候因为使用d_id,d_username这种列名,所以要有ResultMap,来知晓与User中的哪些属性来对应,否则查出来的都是null。
public interface UserMapper {
// @Insert("insert into t_user(username,password,age) values (#{username},#{password},#{age})")
// @Options(keyColumn = "id",keyProperty = "id",useGeneratedKeys = true)
void save(User u);
// @Update("update t_user set username=#{username},password=#{password},age=#{age} where id = #{id}")
void update(User u);
// @Select("select id,username,password,age from t_user where id = #{id}")
User get(Long id);
// @Select("select id as d_id,username as d_username,password as d_password,age as d_age from t_user")
// @ResultMap("base_map") 用配置文件中的base_map
// @Results({ //不用配置文件中的base_map
// @Result(column = "d_id",property = "id"),
// @Result(column = "d_username",property = "username"),
// @Result(column = "d_password",property = "password"),
// @Result(column = "d_age",property = "age"),
// })
List<User> list();
// @Delete("delete from t_user where id = #{id}")
void delete(Long id);
}
以上可替代下面的内容:
<resultMap id="base_map" type="User">
<!--column:查询出来的字段名
property:对象中属性名-->
<id column="d_id" property="id"></id>
<result column="d_username" property="username"></result>
<result column="d_password" property="password"></result>
<result column="d_age" property="age"></result>
</resultMap>
<!--
inser表示插入语句
parameterType表示调用insert传入的参数
keyColumn表示数据库中自增长的字段名
keyProperty表示自增长的字段值应该注入到实体中的哪个字段
useGeneratedKeys表示标记这个标签需要使用数据库中的自增长id
-->
<insert id="save" parameterType="User" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
insert into t_user(username,password,age) values (#{username},#{password},#{age})
</insert>
<update id="update" parameterType="User">
update t_user set username=#{username},password=#{password},age=#{age} where id = #{id}
</update>
<!--
parameterType:
resultType:表示查询出来的每一条结果封装成User对象
-->
<select id="get" parameterType="long" resultType="User">
select id,username,password,age from t_user where id = #{id}
</select>
<!--resultType:表示查询出来的每一条结果封装成User对象
resultType与resultMap不可混用-->
<select id="list" resultMap="base_map">
select id as d_id,username as d_username,password as d_password,age as d_age from t_user
</select>
<delete id="delete" parameterType="java.lang.Long">
delete from t_user where id = #{id}
</delete>
知识点二.使用@param的注解
问题:mybatis中的方法都是只支持传入一个参数。
如果想传入多个参数.
注意此处要指定resultType
<select id="login" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>
mapper接口中常规如下
1.在方法参数定义Map集合,把需要传入的参数放入map中.
User login(Map<String,Object> map);
测试类中常规:
Map<String,Object> uMap = new HashMap<String,Object>();
uMap.put("username","卡丁");
uMap.put("password","66");
User u = mapper.login(uMap);
System.out.println(u);
使用了@param之后
mapper接口中如下:
2.使用@Param注解来解决.
User login(@Param("username") String username,@Param("password") String password);
测试类中:
User u = mapper.login("卡丁","66");
System.out.println(u);
其原理:
知识点三.MyBatis对象关系映射细节
1.Many2One员工2部门
员工(Employee)和部门(Department),多对一:员工表中含有外键(部门号)
domain包:
public class Employee {
private Long id;
private String name;
private Department dept;
public Employee() {
}
public Employee(String name) {
this.name = name;
}
//getter setter方法略
}
public class Department {
private Long id;
private String name;
public Department() {
}
public Department(String name) {
this.name = name;
}
//getter setter略去
}
主配置文件添加mapper,添加别名
<typeAliases>
<typeAlias type="com.mxl.mybatis01_hello.domain.User" alias="User"/>
<typeAlias type="com.mxl.mybatis02_day02.domain.Employee" alias="Employee"/>
<typeAlias type="com.mxl.mybatis02_day02.domain.Department" alias="Department"/>
</typeAliases>
<mappers>
<mapper resource="com/mxl/mybatis01_hello/UserMapper.xml"></mapper>
<mapper resource="com/mxl/mybatis02_day02/EmployeeMapper.xml"></mapper>
<mapper resource="com/mxl/mybatis02_day02/DepartmentMapper.xml"></mapper>
</mappers>
两mapper接口
public interface EmployeeMapper {
void save(Employee e);
Employee get(Long id);
}
---------------------------
public interface DepartmentMapper {
void save(Department d);
Department get(Long id);
}
两mapper.xml文件
== 注意此处insert中部门号要#{dept.id},就是说从dept中找id==
<mapper namespace="com.mxl.mybatis02_day02.mapper.EmployeeMapper">
<insert id="save" parameterType="Employee" keyColumn="id"
keyProperty="id" useGeneratedKeys="true">
insert into t_employee(name,dept_id) values (#{name},#{dept.id})
</insert>
<select id="get" parameterType="long" resultType="Employee">
select id,name,dept_id from t_employee where id = #{id}
</select>
</mapper>
<mapper namespace="com.mxl.mybatis02_day02.mapper.DepartmentMapper">
<insert id="save" parameterType="Department" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
insert into t_department(name) values (#{name})
</insert>
<select id="get" parameterType="long" resultType="Department">
select id,name from t_department where id = #{id}
</select>
</mapper>
测试类:
注意:此处many2one的保存操作,要先保存one方,再保存many方
1.保存
@Test
public void testSave(){
SqlSession session = MybatisUtils.openSession();
EmployeeMapper eMapper = session.getMapper(EmployeeMapper.class);
DepartmentMapper dMapper = session.getMapper(DepartmentMapper.class);
Employee e = new Employee();
Department d = new Department();
d.setName("一号部门");
e.setName("一号员工");
e.setDept(d);
dMapper.save(d);
eMapper.save(e);
session.commit();
session.close();
}
}
2.查询
这里有坑需要注意:
简单的查,是不能通过员工把部门也查询出来的,所以EmployeeMapper.xml要配置resultMap
<mapper namespace="com.mxl.mybatis02_day02.mapper.EmployeeMapper">
<!--
property:表示实体类的关联关系属性名
column:哪个字段
javaType:实体类类型
select:表示需要发送sql去查询
其实配置这里的目的就是要调用Department中的get
-->
<resultMap id="base_map" type="Employee">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<association column="dept_id" property="dept"
javaType="Department" select="com.mxl.mybatis02_day02.mapper.DepartmentMapper.get">
</association>
</resultMap>
<insert id="save" parameterType="Employee" keyColumn="id"
keyProperty="id" useGeneratedKeys="true">
insert into t_employee(name,dept_id) values (#{name},#{dept.id})
</insert>
<select id="get" parameterType="long" resultMap="base_map">
select id,name,dept_id from t_employee where id = #{id}
</select>
</mapper>
myBatis中的延时加载.
1.在myBatis中默认的延时加载时禁用的.
在主配置文件中开启延时加载
lazyLoadingEnabled:默认为false,禁用延时加载.
2.many变成代理对象.
当调用many方的任意属性,都会触发one方的加载.
aggressiveLazyLoading:当启用时, 有延迟加载属性的对象在被调用时将会完全加载任意属性。否则, 每种属性将会按需要加载。
3.在many方默认的调用equals,clone,hashCode,toString 方法都会出发one方的加载
lazyLoadTriggerMethods
主配置文件中配置settings
<settings>
<!--全局启用或禁用延迟加载。当禁用时, 所有关联对象都会即时加载。默认为flase-->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当启用时, 有延迟加载属性的对象在被调用时将会完全加载任意属性.禁用则每种属性将会按需要加载。-->
<setting name="aggressiveLazyLoading" value="false"/>
<!--Object对象上面的哪些方法触发延迟加载.默认equals,clone,hashCode,toString-->
<setting name="lazyLoadTriggerMethods" value="clone"/>
</settings>
N+1问题
在查询所有many记录,每个many对应的one都是不同,查询N个many对象,总共会发出N+1条SQL.(性能特别不友好)
使用leftJoin的方式来解决.
这里写于resultMap中,不采用发sql的方式
<association property="dept" javaType="Department">
<result column="dept_id" property="id"/>
<result column="dept_name" property="name"></result>
</association>
--------------------------
<select id="list" resultMap="base_map">
SELECT e.id,e.name,d.id AS dept_id,d.name AS dept_name FROM t_employee e LEFT JOIN t_department d ON d.id=e.dept_id
</select>
dept_ 采用 columnPrefix措施简化
<association property="dept" javaType="Department" columnPrefix="dept_">
<result column="id" property="id"/>
<result column="name" property="name"></result>
</association>
一级缓存
生命周期:
和session一样的生命周期.
通过session.get(1L),session.get(1L),总共两次get方法只会发一条SQL.第二次使用的是一级缓存的内容
//清除一级缓存中内容
session.clearCache();
针对数据量大的时候,使用分页+clearCache()及时清除缓存
2.One2Many部门2员工
one需要处理外键关系
员工类中的dept_id属性删除,并在部门类中增加员工对象emps.
public class Department {
private Long id;
private String name;
private List<Employee> emps = new ArrayList<Employee>();
public Department() {
}
public Department(String name) {
this.name = name;
}
//getter setter方法
//toString方法(id,name)
}
主配置文件中定义别名,注册mapper:
<typeAliases>
<typeAlias type="com.mxl.mybatis02_day02.one2many.domain.Employee" alias="Employee"/>
<typeAlias type="com.mxl.mybatis02_day02.one2many.domain.Department" alias="Department"/>
</typeAliases>
<mappers>
<!--one2many-->
<mapper resource="com/mxl/mybatis02_day02/one2many/EmployeeMapper.xml"></mapper>
<mapper resource="com/mxl/mybatis02_day02/one2many/DepartmentMapper.xml"></mapper>
</mappers>
两个mapper接口
public interface DepartmentMapper {
void save(Department e);
Department get(Long id);
void handlerRelation(@Param("deptId")Long deptId,@Param("empId")Long empId);
}
----------------------------
public interface EmployeeMapper {
void save(Employee e);
Employee get(Long id);
}
两个mapper文件
<mapper namespace="com.mxl.mybatis02_day02.one2many.mapper.DepartmentMapper">
<resultMap id="base_map" type="Department">
<id column="id" property="id"/>
<result property="name" column="name"/>
<!--
ofType:查询出来集合中的类型
<collection column="id" property="emps" ofType="Employee" select="com.mxl.mybatis02_day02.one2many.mapper.EmployeeMapper.selectByDeptId"/>
-->
<collection property="emps" ofType="Employee">
<result></result>
</collection>
</resultMap>
<select id="get" parameterType="long" resultMap="base_map">
select id,name from t_department where id = #{id}
</select>
<insert id="save" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
insert into t_department (name) values (#{name})
</insert>
<update id="handlerRelation">
update t_employee set dept_id = #{deptId} where id = #{empId}
</update>
</mapper>
<mapper namespace="com.mxl.mybatis02_day02.one2many.mapper.EmployeeMapper">
<insert id="save" keyProperty="id" keyColumn="id" parameterType="Employee" useGeneratedKeys="true">
insert into t_employee (name) values (#{name})
</insert>
<select id="get" parameterType="long" resultType="Employee">
select id,name,dept_id where id = #{id}
</select>
<select id="selectByDeptId" resultType="Employee">
select id,name from t_employee where dept_id = #{deptId}
</select>
</mapper>
测试:
public class TestOne2Many {
@Test
public void test01() {
SqlSession session = MybatisUtils.openSession();
EmployeeMapper eMapper = session.getMapper(EmployeeMapper.class);
DepartmentMapper dMapper = session.getMapper(DepartmentMapper.class);
Employee e1 = new Employee("一号员工");
Employee e2 = new Employee("二号员工");
Department d = new Department("一号部门");
d.getEmps().add(e1);
d.getEmps().add(e2);
eMapper.save(e1);
eMapper.save(e2);
dMapper.save(d);
//需要由one方去处理外键关系
List<Employee> es = d.getEmps();
for (Employee e : es) {
dMapper.handlerRelation(d.getId(),e.getId());
}
session.commit();
session.close();
}
@Test
public void testGet() {
SqlSession session = MybatisUtils.openSession();
DepartmentMapper dMapper = session.getMapper(DepartmentMapper.class);
Department dept = dMapper.get(22L);
System.out.println(dept);
List<Employee> emps = dept.getEmps();
for (Employee emp : emps) {
System.out.println(emp);
}
session.close();
}
}
3.many2many(教师2学生)
在这个地方,犯了个错误,就是用insert,update,delete更改数据库中的内容的时候,切记session.commit操作,要不然数据库中内容不会改变.
保存操作如下:
1.建数据库表,学生表,教师表,中间表(学生id,教师id)
2.教师类学生类分别提供id,name属性,无参及有参(name)构造器,对应属性的getter,setter方法.
3.在主配置文件中定义别名,并注册对应mapper.xml.
4.两个mapper接口
public interface StudentMapper {
void save(Student t);
}
---------------------------------
public interface TeacherMapper {
void save(Teacher t);
void handlerRelation(@Param("teaId")Long teaId,@Param("stuId")Long stuId);
}
两个mapper.xml文件,注意TeacherMapperz中的handlerRelation
<mapper namespace="com.mxl.mybatis02_day02.many2many.mapper.StudentMapper">
<insert id="save" parameterType="Student" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
insert into t_student(name) values (#{name})
</insert>
</mapper>
-------------------------------------------------------
<mapper namespace="com.mxl.mybatis02_day02.many2many.mapper.TeacherMapper">
<insert id="save" parameterType="Teacher" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
insert into t_teacher(name) values (#{name})
</insert>
<insert id="handlerRelation">
insert into tea_stu (t_id,s_id) values (#{teaId},#{stuId})
</insert>
</mapper>
测试类:
@Test
public void test(){
Teacher t1 = new Teacher();
t1.setName("老师一");
Teacher t2 = new Teacher();
t2.setName("老师二");
Student s1 = new Student();
s1.setName("学生一");
Student s2 = new Student();
s2.setName("学生二");
t1.getStus().add(s1);
t1.getStus().add(s2);
t2.getStus().add(s1);
t2.getStus().add(s2);
SqlSession session = MybatisUtils.openSession();
TeacherMapper tMapper = session.getMapper(TeacherMapper.class);
StudentMapper sMapper = session.getMapper(StudentMapper.class);
tMapper.save(t1);
tMapper.save(t2);
sMapper.save(s1);
sMapper.save(s2);
//来处理中间表的的关系
List<Student> t1Stus = t1.getStus();
for (Student student : t1Stus) {
tMapper.handlerRelation(t1.getId(),student.getId());
System.out.println(student);
}
List<Student> t2Stus = t2.getStus();
for (Student student : t2Stus) {
tMapper.handlerRelation(t2.getId(),student.getId());
System.out.println(student);
}
session.commit();
session.close();
}
查询操作
注意
resuilMap代替resultType
mapper接口中提供get方法.
public interface StudentMapper {
Student get(Long id);
}
---------------------------------------
public interface TeacherMapper {
Teacher get(Long id);
}
mapper的xml文件中:
StudentMapper
<select id="selectByTeaId" parameterType="long" resultType="Student">
SELECT * FROM t_student WHERE id IN
(SELECT s_id FROM tea_stu WHERE t_id IN
(SELECT id FROM t_teacher WHERE id = #{teaId}))
</select>
TeacherMapper
<resultMap id="base_map" type="Teacher">
<id column="id" property="id"/>
<result property="name" column="name"/>
<collection
property="stus"
ofType="Student"
column="id"
select="com.mxl.mybatis02_day02.many2many.mapper.StudentMapper.selectByTeaId"/>
</resultMap>
<select id="get" parameterType="long" resultMap="base_map">
select id,name from t_teacher where id = #{id}
</select>
测试:
@Test
public void testQ(){
SqlSession session = MybatisUtils.openSession();
TeacherMapper tMapper = session.getMapper(TeacherMapper.class);
Teacher teacher = tMapper.get(9L);
List<Student> stus = teacher.getStus();
for (Student student : stus) {
System.out.println(student);
}
System.out.println(teacher);
session.close();
}
-----------------------分隔符---------------------------------------------------
spring与mybatis简单集成(jar):
Mapper的使用
1.把mapper当做是Dao辅助工具
2.直接将mapper当做是Dao.
步骤:
1.导入相关的资源包
1.myBatis自身的包
2.spring相关的包
3.spring-mybatis-plugins.jar整合
数据库连接池druid.
2.创建resources添加配置文件
3.编写配置文件
1.导入外部文件db.properties
2.配置数据源
3.配置sessionFactory
4.配置事务管理器
5.配置事务模板
6.AOP切面配置
定义service,Mapper对应bean.
application.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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--注解扫描-->
<context:component-scan base-package="com.mxl.crm"/>
<!--1.导入外部文件db.properties-->
<context:property-placeholder location="classpath:db.properties"/>
<!--2.配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${db.driverClassName}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<!--3.配置sessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/mxl/crm/mappper/*Mapper.xml"/>
<!--4.配置别名-->
<property name="typeAliasesPackage" value="com.mxl.crm.domain"/>
</bean>
<!--5.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--6.配置事务模板-->
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="list*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--7.配置aop切面-->
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.mxl.crm.service.*.*(..))"/>
<aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
</aop:config>
<!--配置mapper-->
<bean id="configurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mxl.crm.mappper"/>
</bean>
<!--配置service,mapper的bean-->
<!--<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--<property name="mapperInterface" value="com.mxl.crm.mappper.UserMapper"></property>-->
<!--</bean>-->
<!--<bean id="userService" class="com.mxl.crm.service.impl.UserServiceImpl">-->
<!--<property name="mapper" ref="userMapper"></property>-->
<!--</bean>-->
</beans>
1.service全都变成注解配置的方式.
2.在配置文件中添加注解扫描的配置
<!--注解扫描-->
<context:component-scan base-package="com.mxl.crm"/>
3.添加扫描mapper的类
<!--配置mapper-->
<bean id="configurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mxl.crm.mappper"/>
</bean>
最后:二级缓存
1.回顾hibernate中的缓存
二级缓存的生命周期和sessionFactory一样的生命周期
什么样类型的对象适合放入二级缓存
读远远大于写的对象.
hibernate中的缓存:
1.一级缓存
2.二级缓存
3.查询缓存(限制很多,命中率比较低)
开启二级缓存后,get (),insert(),get(); 总共发2条sql
MyBatis中的二级缓存.
一般来说,我们将myBatis中二级缓存说成是myBatis缓存
步骤:
1.需要在mapper文件中添加<cache />
2.缓存的对象需要实现序列化接口
myBatis开启二级缓存后,get (),insert(),get(); 总共发3条sql
在mybatis中无论是selectOne还是selectList都是使用查询缓存.当对象新增,更新,删除的时候,都回去清空查询缓存
让myBatis的缓存和hibernate中的二级缓存靠近
步骤:
1.让所有list都不是缓存 userCache=false
2.让新增操作不清空缓存. flashCache=false