没有结果的努力不叫努力
1.将连接工厂的操作写成工具类
MyBatisUtil
package com.mybatis.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
static SqlSession sqlSession;
static SqlSessionFactory sqlSessionFactory;
static {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("SqlMapConfig.xml"));
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
public static SqlSession getSession(boolean autoCommit) {
return sqlSessionFactory == null ? null : sqlSessionFactory.openSession(autoCommit);
}
public static void close(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close();
}
}
}
2.不写mapper.xml,采用注解形式
StudentMapper
package com.mybatis.mapper;
import com.mybatis.entity.Student;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/*
* 注解方式
* */
public interface StudentMapper {
@Select("select * from mybatis_student where name like concat('%',#{value},'%')")
List<Student> selectStudentByName(String Studentname);
@Select("select * from mybatis_student where id=#{value}")
Student selectStudentById(Long id);
@Select("select * from mybatis_student")
List<Student> selectAllStudents();
void delectStudentById(Long id);
long countStudent();
}
3.动态SQL
根据实体类的不同取值,使用不同的SQL语句来进行查询,比如在id如果不为空时可以根据id查询,如果username不为空时还要加入用户名作为条件
测试类运行
package com.mybatis.mapper;
import com.mybatis.entity.Student;
import com.mybatis.util.MyBatisUtil;
import junit.framework.TestCase;
import org.junit.Test;
public class StudentMapperTest extends TestCase {
StudentMapper mapper=MyBatisUtil.getSession(true).getMapper(StudentMapper.class);
public void testSelectStudentByName() {
mapper.selectStudentByName("a").forEach(System.out::println);
}
public void testSelectStudentById() {
Student student =mapper.selectStudentById(1L);
System.out.println(student);
}
@Test
public void testSelectAllStudents() {
mapper.selectAllStudents().forEach(System.out::println);
}
public void testDelectStudentById() {
}
public void testCountStudent() {
}
}
运行结果
4.p6spy用来探测生成的SQL语句中的?的真实值
(1)安装相应的jar包
(2)将数据库连接的驱动换成p6spy的连接
(3)p6spy的数据库连接之前的驱动
按照教程配置,但是控制台不显示,我也不知道为什么
显示在spy.log文件中了
5.sql片段
<sql id="select_user">
select * from mybatis_user
</sql>
<!-- 根据id查询用户-->
<select id="selectUserById" parameterType="java.lang.Long" resultType="user">
<include refid="select_user"></include>
where id=#{value}
</select>
6.多表查询(一对一)
创建返回Map类,进行映射
<?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:填写映射当前的Mapper接口,所有的增删改查的参数和返回值类型,
就可以直接填写缩写,不区分大小写,直接通过方法名去找类型-->
<mapper namespace="com.mybatis.mapper.StudentMapper">
<!--一对一关联查询-->
<select id="selectStudentById" parameterType="java.lang.Long" resultMap="scMap">
select s.*,c.id cid, c.name cname from mybatis.mybatis_student s join mybatis.mybatis_clazz c on s.clazz_id=c.id
where s.id=#{value}
</select>
<!--关联查询的映射-->
<resultMap id="scMap" type="student">
<!--学生主键-->
<id property="id" column="id"/>
<!--学生其他属性-->
<result column="name" property="name"/>
<result column="gender" property="gender"/>
<result column="birthday" property="birthday"/>
<!--班级信息(一对一)-->
<association property="clazz" column="clazz">
<!--班级主键-->
<id column="cid" property="id"/>
<!--班级其他属性-->
<result column="cname" property="name"/>
</association>
</resultMap>
</mapper>
(一对多)
<?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:填写映射当前的Mapper接口,所有的增删改查的参数和返回值类型,
就可以直接填写缩写,不区分大小写,直接通过方法名去找类型-->
<mapper namespace="com.mybatis.mapper.ClazzMapper">
<select id="selectClazzById" resultMap="csMap">
select c.id cid,c.name cname,s.* from mybatis_clazz c left join mybatis_student s
on s.clazz_id=c.id where c.id=#{value}
</select>
<resultMap id="csMap" type="clazz">
<id property="id" column="cid"/>
<result property="name" column="cname"/>
<!--一对多-->
<collection property="students" ofType="student">
<id property="id" column="id"/>
<result column="name" property="name"/>
<result column="gender" property="gender"/>
<result column="birthday" property="birthday"/>
</collection>
</resultMap>
</mapper>
association映射的是一个JavaBean类,它仅处理一对一的关联关系。
collection则是映射的一个集合列表,它处理的是一对多的关联关系。
自增id
插入数据后,把数据库自增id回绑到对象中selectKey
<?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:填写映射当前的Mapper接口,所有的增删改查的参数和返回值类型,
就可以直接填写缩写,不区分大小写,直接通过方法名去找类型-->
<mapper namespace="com.mybatis.mapper.StudentMapper">
<!--添加学生-->
<insert id="insertStudent" parameterType="student">
-- order表示何时计算主键值;oracle数据库使用序列进行自增,所以要使用before;mysql数据库使用LAST_INSERT_ID()函数计算,使用After
<selectKey keyProperty="id" resultType="long" order="AFTER">
select LAST_INSERT_ID() from dual
</selectKey>
insert into mybatis_student(name,gender,birthday,clazz_id) values (#{name},#{gender},#{birthday},#{clazz.id})
</insert>
<!--一对一关联查询-->
<select id="selectStudentById" parameterType="java.lang.Long" resultMap="scMap">
select s.*,c.id cid, c.name cname from mybatis.mybatis_student s join mybatis.mybatis_clazz c on s.clazz_id=c.id
where s.id=#{value}
</select>
<!--关联查询的映射-->
<resultMap id="scMap" type="student">
<!--学生主键-->
<id property="id" column="id"/>
<!--学生其他属性-->
<result column="name" property="name"/>
<result column="gender" property="gender"/>
<result column="birthday" property="birthday"/>
<!--班级信息(一对一)-->
<association property="clazz" column="clazz">
<!--班级主键-->
<id column="cid" property="id"/>
<!--班级其他属性-->
<result column="cname" property="name"/>
</association>
</resultMap>
</mapper>
7.延迟加载
https://www.cnblogs.com/neon/p/10940346.html
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称为懒加载。
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
customer
package com.mybatis.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
private Long id;
private String name;
private List<Order> orders;
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
order
package com.mybatis.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Long id;
private String orderno;
private Double price;
private Date createDate;
private Customer customer;
@Override
public String toString() {
return "Order{" +
"id=" + id +
", orderno='" + orderno + '\'' +
", price=" + price +
", create=" + createDate +
'}';
}
}
CustomerAndOrderMapper
package com.mybatis.mapper;
import com.mybatis.entity.Customer;
public interface CustomerAndOrderMapper {
/**
* 查询顾客,如果顾客有订单,则级联查询出订单信息
* 懒加载模式
* */
Customer selectCustomerAndOrderById(Long id);
}
CustomerAndOrderMapper.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:填写映射当前的Mapper接口,所有的增删改查的参数和返回值类型,
就可以直接填写缩写,不区分大小写,直接通过方法名去找类型-->
<mapper namespace="com.mybatis.mapper.CustomerAndOrderMapper">
<select id="selectCustomerAndOrderById" parameterType="long" resultMap="coMap">
select id,name from mybatis_customer where id=#{value}
</select>
<select id="selectOrderByCustomerId" parameterType="long" resultType="order">
select * from mybatis_order where customer_id=#{value}
</select>
<resultMap id="coMap" type="customer">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--提供了延迟加载-->
<collection property="orders" ofType="order" select="selectOrderByCustomerId" column="id"/>
</resultMap>
</mapper>
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>
<!--加载数据库配置文件-->
<!-- <properties resource="db.properties"/>-->
<!--配置properties-->
<properties>
<property name="driver" value="com.p6spy.engine.spy.P6SpyDriver"></property>
<property name="url" value="jdbc:p6spy:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</properties>
<settings>
<!--开启延迟加载的支持-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 别名设置,全路径名改成类名-->
<typeAliases>
<!-- 该包下面实体类全部采用别名形式-->
<package name="com.mybatis.entity"/>
</typeAliases>
<!-- 使用mybatis内置的枚举转换器(默认String)-->
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="com.mybatis.entity.Gender"></typeHandler>
</typeHandlers>
<!--数据库配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.mybatis.mapper"></package>
<!-- <mapper resource="com/mybatis/mapper/UserMapper.xml"></mapper>-->
</mappers>
</configuration>
CustomerAndOrderMapperTest
package com.mybatis.mapper;
import com.mybatis.entity.Customer;
import com.mybatis.util.MyBatisUtil;
import junit.framework.TestCase;
public class CustomerAndOrderMapperTest extends TestCase {
CustomerAndOrderMapper mapper = MyBatisUtil.getSession(true).getMapper(CustomerAndOrderMapper.class);
public void testSelectCustomerAndOrderById() {
Customer customer = mapper.selectCustomerAndOrderById(1L);
//如果只使用顾客,则延迟加载策略会暂时屏蔽订单的查询
System.out.println(customer);
//当要使用订单信息时,将会打破延迟加载,查询订单信息
customer.getOrders().forEach(System.out::println);
}
}
运行结果
8.一级缓存
当第一次时,和数据库发生交互,执行SQL语句,并且把查询到的数据放入缓存中。如果第二次查询,查询的内容是一样的,则直接从一级缓存中获取数据,不和数据库发生交互,从而提高查询性能。
注意:如果查询后把sqlsession提交或关闭了,则一级缓存数据将清空。
9.二级缓存
作用范围是sqlsessionfactory,是多个sqlsession共享,默认关闭,需要配置开启,
可以使用默认的缓存,也可以使用第三方缓存工具(ehcache)
配置方法
1.在mapper.xml映射文件中添加<cache></cache>
2.在sql标签中使用useCache=true
3.把实体类实现java.io.serializable接口
企业使用数据库代替缓存redis
10.PageHelper
11.逆向工程
用的不多