一、简单实现操作
- 配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>icu.yyykstudy</groupId>
<artifactId>Mybatis-Study</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>mybatis-01</module>
</modules>
<!--导入依赖-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
</dependencies>
<!--过滤静态资源-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
-
右键项目名 --> new --> Module — 创建一个项目
-
src --> java下创建dao,pojo,utils包
-
utils下创建MybatisUtils
package icu.yyykstudy.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
//SqlSessionFactory --> SqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//第一步:获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
- pojo下创建User
package icu.yyykstudy.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
- dao下创建UserMapper
package icu.yyykstudy.dao;
import icu.yyykstudy.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper {
public List<User> getUserList();
public User getUserById(@Param("id") int id);
public int insert(User user);
public int update(User user);
// 不加@Param也可以
public int deleteById(int id);
}
- dao下创建UserMapper.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=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="icu.yyykstudy.dao.UserMapper">
<select id="getUserList" resultType="icu.yyykstudy.pojo.User">
select * from mybatis.user
</select>
<select id="getUserById" parameterType="int" resultType="icu.yyykstudy.pojo.User">
select *
from mybatis.user
where id = #{id};
</select>
<insert id="insert" parameterType="icu.yyykstudy.pojo.User">
insert into mybatis.user(id, name, pwd)
values (#{id},#{name},#{pwd});
</insert>
<update id="update" parameterType="icu.yyykstudy.pojo.User">
update mybatis.user
set name = #{name},pwd = #{pwd}
where id = #{id};
</update>
<delete id="deleteById" parameterType="int">
delete from mybatis.user where id = #{id};
</delete>
</mapper>
- resources下创建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:核心配置文件-->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8"/>
<property name="username" value="lyyykstudy"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers>
<mapper resource="icu/yyykstudy/dao/UserMapper.xml"></mapper>
</mappers>
</configuration>
- 测试
package icu.yyykstudy.dao;
import icu.yyykstudy.pojo.User;
import icu.yyykstudy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
@Test
public void getUserList(){
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in); //将配置文件中的property和mapper对应的class或resouce中的Mapper打包到Configuration中
//3.使用工厂生产SqlSession对象
SqlSession sqlSession = factory.openSession();
try{
//4.使用SqlSession创建Dao接口的代理对象并执行方法
/*方式一:getMapper //生成一个代理对象
public <T> T getMapper(Class<T> daoInterfaceClass) {
return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),new Class[]{daoInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
}
*/
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//使用代理对象执行方法
List<User> userList = mapper.getUserList();
//方式二:不生成代理对象,可以自己写一个实现UserMapper接口的类,但是这样很麻烦,不如直接代理
List<User> userList = sqlSession.selectList("icu.yyykstudy.dao.userdao.getUserList"); //类名+方法名icu.yyykstudy.dao.userdao.getUserList
for (User user : userList) {
System.out.println(user);
}
}finally {
//5.释放资源
in.close();
sqlSession.close();
}
}
//也可这样写,调用MybatisUtils下的getSqlSession()方法
@Test
public void getUserList(){
//第一步:获得SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
//第二步:执行SQL
//方式一:getMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
//方式二:老方法,不建议写
// List<User> userList = sqlSession.selectList("icu.yyykstudy.dao.userdao.getUserList");
for (User user : userList) {
System.out.println(user);
}
}finally {
sqlSession.close();
}
}
//增删改需要提交事务
@Test
public void insert(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.insert(new User(3, "赵五", "123456"));
if(res>0){
System.out.println("插入成功");
sqlSession.commit();
}else
sqlSession.rollback();
}finally {
sqlSession.close();
}
}
@Test
public void update(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.update(new User(3, "王五", "123456"));
if(res>0){
System.out.println("更新成功");
sqlSession.commit();
}else
sqlSession.rollback();
}finally {
sqlSession.close();
}
}
@Test
public void delete(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.deleteById(3);
if(res>0){
System.out.println("删除成功");
sqlSession.commit();
}else
sqlSession.rollback();
}finally {
sqlSession.close();
}
}
}
二、入门知识点
首先实体类的属性名须和数据库名一样,否则很麻烦,后面有讲
1. parameterType:接受参数类型(多用于增删改)
· 基本类型:如int,Integer,java.lang.Integer
· 实体类型:icu.yyykstudy.pojo.User
2. resultType:返回类型(多用于查询)
· 基本类型:如int,Integer,java.lang.Integer
· 实体类型:icu.yyykstudy.pojo.User
3. resultMap:结果集映射,只能解决结果集返回时类属性名和数据库字段名不匹配问题,并不能解决传值时的问题
<!-- 定义User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id> <!-- 主键ID-->
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
3. #{“value”}中的value
· 基本类型:若方法只有一个参数写什么名字都行,若有很多可在方法名的参数前加@Param(“value”)来区分
· 实体类型:User中的get,set方法必须是自动生成的!!!直接写属性名!若User中还有Animal实体类对象,可以通过animal.name得到其属性值。
4. 通过注解或映射文件代理Dao接口
<mappers>
<mapper resource="icu/yyykstudy/dao/IUserDao.xml"/> <!-- 使用映射配置文件 -->
<mapper class="icu.yyykstudy.dao.IUserDao"/> <!-- 使用注解 -->
</mappers>
5.配置别名
在 mybatis-config.xml 中配置:
定义pojo下的类名
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="icu.yyyksutdy.pojo.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.itheima.domain"/>
<package name="其它包"/>
</typeAliases>
定义mapper(dao)包下的类名
<!---->
<mapper resource="com/itheima/dao/IUserDao.xml" />
<mapper class="com.itheima.dao.UserDao"/>
<!--★注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。-->
6.对于SQL语句中含有where且有未知判断参数用if标签
在映射配置文件UserMapper.xml中使用if语句判断判断的有什么参数
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user where 1=1
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
</select>
也可不用写where 1=1,那在配置文件的if标签前加where标签
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user
<where>
<if test="usersame != null">
and username = #{userName}
</if>
<if test="usersex != null">
and sex = #{userSex}
</if>
</where>
</select>
foreach标签
用来遍历SQL语句中一个属性中多个值
List<User> findUserInIds(QueryVo vo); //QueryVo ---> private List<Integer> ids;
<!-- 了解的内容:抽取重复的sql语句-->
<sql id="defaultUser">
select * from user
</sql>
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
<include refid="defaultUser"></include> <!-- select * from user -->
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
collection为遍历集合
item为集合中的每一个值
open,close只执行一次,分别为开头和结束
separator为分隔符
三、知识点
1.模糊查询
第一种:简单字符串拼接
List<User> list = mapper.queryByname("%"+name+"%");
<select id="queryByname" parameterType="string" resultType="icu.yyykstudy.pojo.User">
select * from user where username like #{name}
</select>
第二种:
List<User> list = udao.queryByname(name);
<select id="queryByname" parameterType="string" resultType="icu.yyykstudy.pojo.User">
select * from user where username like '%${value}%' //⭐若传入一个变量此处只能写value,与底层代码有关,若传入一个实体类,可通过聚合函数concat('%',#{},'%')实现
</select>
第二种更为好用,防止SQL注入
2.得到插入后的ID
数据库中查询新插入的ID的SQL语句
select last_insert_id();
在配置文件中
<insert id="insert" parameterType="icu.yyykstudy.pojo.User">
<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int"> //keyColumn:属性名 keyColumn:数据库字段名
select last_insert_id();
</selectKey>
insert into user(username) value (#{name});
</insert>
User user = new User("小狗");
udao.insert(user); //执行此方法后,user中的id由null变为刚插入的id值
3.类属性名和数据库字段名不匹配问题
在映射文件中添加
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="userMap" type="icu.yyykstudy.pojo.User">
<!-- 主键字段的对应 -->
<id property="userId" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
<select id="findAll" resultMap="userMap">
<!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;-->
select * from user;
</select>
4.mybatis连接池
Mybatis将它自己的数据源分为三类:
UNPOOLED 不使用连接池的数据源
POOLED 使用连接池的数据源
JNDI 使用JNDI 实现的数据源(见7)
在dataSouce的type属性中修改
<!-- 配置数据源(连接池)信息 --> <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>
MyBatis 在初始化时,根据dataSource的 type 属性来创建相应类型的的数据源 DataSource,即:
type=“POOLED”:MyBatis 会创建 PooledDataSource 实例
type=“UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
type=“JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
PooledDataSource工作原理
5.mybatis事务
session = factory.openSession(true); //事务关自动提交,底层就是JDBC的connection.setAutoCommit(false)
6.mybatis中pojo包建类思想
一对一
一个账户有一个用户
Account类
private Integer id;
private Integer uid;
private Double money;
//从表实体应该包含一个主表实体的对象引用
private User user;
AccountMapper.xml中
<!-- 定义封装account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射:配置封装user的内容-->
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
</select>
一对多
一个用户有多个账户
User:
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多关系映射:主表实体应该包含从表实体的集合引用
private List<Account> accounts;
UserMapper.xml中
<!-- 定义User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
多对多
多个人对应多个角色
实体类
User
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//多对多的关系映射:一个用户可以具备多个角色
private List<Role> roles;
Role
private Integer roleId;
private String roleName;
private String roleDesc;
//多对多的关系映射:一个角色可以赋予多个用户
private List<User> users;
映射文件
IUserMapper.xml
<!-- 定义User的resultMap-->
<resultMap id="userMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置角色集合的映射 -->
<collection property="roles" ofType="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userMap">
select u.*,r.id as rid,r.role_name,r.role_desc from user u
left outer join user_role ur on u.id = ur.uid
left outer join role r on r.id = ur.rid
</select>
IRoleMapper.xml
<!--定义role表的ResultMap-->
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
<!--查询所有-->
<select id="findAll" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r
left outer join user_role ur on r.id = ur.rid
left outer join user u on u.id = ur.uid
</select>
其次,数据库中也要有对应的两个表user,role,和一个中间表user_role,并且得有外键,一对多也要有外键,最好不要用物理外键,在代码中写比较。
7.创建JNDI项目
- 创建web项目
- META-INF下创建context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!--
<Resource
name="jdbc/eesy_mybatis" 数据源的名称
type="javax.sql.DataSource" 数据源类型
auth="Container" 数据源提供者
maxActive="20" 最大活动数
maxWait="10000" 最大等待时间
maxIdle="5" 最大空闲数
username="root" 用户名
password="1234" 密码
driverClassName="com.mysql.jdbc.Driver" 驱动类
url="jdbc:mysql://localhost:3306/eesy_mybatis" 连接url字符串
/>
-->
<Resource
name="jdbc/eesy_mybatis"
type="javax.sql.DataSource"
auth="Container"
maxActive="20"
maxWait="10000"
maxIdle="5"
username="root"
password="1234"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/eesy_mybatis"
/>
</Context>
- mybatis-config.xml中dataSource中配置JNDI
<!-- 配置mybatis的环境 -->
<environments default="mysql">
<!-- 配置mysql的环境 -->
<environment id="mysql">
<!-- 配置事务控制的方式 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的必备信息 type属性表示是否使用数据源(连接池)-->
<dataSource type="JNDI">
<property name="data_source" value="java:comp/env/jdbc/eesy_mybatis"/>
</dataSource>
</environment>
</environments>
- jsp中测试
<html>
<body>
<h2>Hello World!</h2>
<%
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.根据配置文件构建SqlSessionFactory
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用SqlSessionFactory创建SqlSession对象
SqlSession sqlSession = factory.openSession();
//4.使用SqlSession构建Dao的代理对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
//5.执行dao中的findAll方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//6.释放资源
sqlSession.close();
in.close();
%>
</body>
</html>
8.延迟加载
问题:
在一对多中,当我们有一个用户,它有100个账户。
在查询用户的时候,要不要把关联的账户查出来?
在查询账户的时候,要不要把关联的用户查出来?
在查询用户时,用户下的账户信息应该是,什么时候使用,什么时候查询的。
在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。
什么是延迟加载?
在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
什么是立即加载?
不管用不用,只要一调用方法,马上发起查询。
在对应的四种表关系中:一对多,多对一,一对一,多对多
一对多,多对多:通常情况下我们都是采用延迟加载。
多对一,一对一:通常情况下我们都是采用立即加载。
- 在mybatis配置中开启懒加载
<!--配置参数-->
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
- 在mapper.xml文件中封装类
一对一
IAccountDao.xml
<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射:配置封装user的内容
select属性指定的内容:查询用户的唯一标识:
column属性指定的内容:用户根据id查询时,所需要的参数的值
-->
<association property="user" column="uid" javaType="user" select="com.itheima.dao.IUserDao.findById"></association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
select * from account
</select>
UserDao.xml
<!-- 根据id查询用户 -->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{uid}
</select>
一对多
UserDao.xml
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
IAccountDao.xml
<!-- 根据用户id查询账户列表 -->
<select id="findAccountByUid" resultType="account">
select * from account where uid = #{uid}
</select>
- 测试
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
}
}
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for(Account account : accounts){
System.out.println("--------每个account的信息------------");
System.out.println(account);
System.out.println(account.getUser());
}
}
很显然,第一次没有用到查询用户的方法,就没有查询信息,用到的时候再一条一条地查询
9.缓存
什么是缓存
存在于内存中的临时数据。
为什么使用缓存
减少和数据库的交互次数,提高执行效率。
什么样的数据能使用缓存,什么样的数据不能使用
适用于缓存:
经常查询并且不经常改变的。
数据的正确与否对最终结果影响不大的。
不适用于缓存:
经常改变的数据
数据的正确与否对最终结果影响很大的。
例如:商品的库存,银行的汇率,股市的牌价。
Mybatis中的一级缓存和二级缓存
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
第三步:让当前的操作支持二级缓存(在select标签中配置)
一级缓存
User user1 = userDao.findById(41);
System.out.println(user1);
User user2 = userDao.findById(41);
System.out.println(user1 == user2); //true
// sqlSession.close();
//再次获取SqlSession对象
// sqlSession = factory.openSession();
sqlSession.clearCache();//此方法也可以清空缓存
userDao = sqlSession.getMapper(IUserDao.class);
User user3 = userDao.findById(41);
System.out.println(user3);
System.out.println(user1 == user3); //false
//1.根据id查询用户
User user1 = userDao.findById(41);
System.out.println(user1);
//2.更新用户信息
user1.setUsername("update user clear cache");
user1.setAddress("北京市海淀区");
userDao.updateUser(user1);
//3.再次查询id为41的用户
User user2 = userDao.findById(41);
System.out.println(user2);
System.out.println(user1 == user2);//false
/*
※一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit()
方法时,就会清空一级缓存。close()等
*/
二级缓存
结构图
- mybatis配置文件
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- Mapper配置文件
<!--开启user支持二级缓存-->
<mapper namespace="com.itheima.dao.IUserDao">
<!--开启user支持二级缓存-->
<cache/>
</mapper>
- Mapper方法标签
<select id="findById" parameterType="INT" resultType="user" useCache="true">
select * from user where id = #{uid}
</select>
注:二级缓存存放的是数据而不是对象,因此查出来的对象地址并不相同。
10.注解开发
1.解决类属性名与数据库名不同
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
})
List<User> findAll();
//这里的Results只需配置一次即可,其他方法可根据id直接引用,后面有用到。
2.一对一
IAccountDao
@Select("select * from account")
@Results(id="accountMap",value = {
@Result(id=true,column = "id",property = "id"),
@Result(column = "uid",property = "uid"),
@Result(column = "money",property = "money"),
@Result(property = "user",column = "uid",one=@One(select="com.itheima.dao.IUserDao.findById",fetchType= FetchType.EAGER))
})
List<Account> findAll();
IUserDao
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
3.一对多
IUserDao
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
@Result(property = "accounts",column = "id",
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();
IAccountDao
@Select("select * from account where uid = #{userId}")
List<Account> findAccountByUid(Integer userId);
4.缓存
一级缓存自动开
二级缓存:
1.mybatis配置文件中配置二级缓存,9中有(不用配置也可,默认开启)
2.mapper接口中加一个注解即可
@CacheNamespace(blocking = true)
public interface IUserMapper {
}
四、一些JDBC知识点
PreparedStatement对象的执行方法
- execute:它能执行CRUD中的任意一种语句。它的返回值是一个boolean类型,表
示是否有结果集。有结果集是true,没有结果集是fasle。 - executeUpdate:它只能执行CUD语句,查询语句无法执行。他的返回值是影响数
据库记录的行数 - executeQuery:它只能执行SELECT语句,无法执行增删改。执行结果封装的结果集ResultSet对象