JavaWeb学习中关于Redis的相关知识 💯💤
MyBatis
¶持久层技术解决方案
- JDBC技术:
- Connection
- PreparedStatement
- ResultSet
- Spring的JdbcTemplate:
- Spring中对jdbc的简单封装
- Apache的DBUtils:
- 和Spring的JdbcTemplate类似,也是对jdbc的简单封装
以上均不是框架,JDBC是规范,Spring的JdbcTemplate和Apache的DBUtils是工具类。
- 使用JDBC存在的一些缺陷
- 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
- Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
- 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
- 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
¶MyBatis框架概述
- mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
- mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。
- 采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。
- ORM(Object Relational Mapping,对象关系映射):把数据库表和实体类以及实体类的属性对应起来,实现操作实体类就可以操作数据库。
¶MyBatis入门
-
创建maven工程并导入相关依赖
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version> </dependency>
-
创建实体类以及对应的Dao接口,如User类和UserMapper接口
public interface UserMapper { /** * 根据id查询一个用户 * * @param userID * @return User */ User findById(Integer id); }
-
在resources文件夹下创建MyBatis主配置文件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"> <!--mybatis主配置文件--> <configuration> <!-- 配置环境 --> <environments default="mysql"> <!--配置mysql环境--> <environment id="mysql"> <!--配置事务类型--> <transactionManager type="JDBC"></transactionManager> <!--配置数据源(连接池)--> <dataSource type="POOLED"> <!--配置连接数据库的四个基本信息--> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件--> <mappers> <mapper resource="cn/sucrelt/dao/UserMapper.xml"/> </mappers> </configuration>
-
在resources文件夹下创建对应的目录,并创建映射配置文件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"> <mapper namespace="cn.sucrelt.dao.UserMapper" resultType="cn.sucrelt.domain.User"> <!--根据id查询一个用户信息--> <select id="findById" parameterType="Integer" resultMap="userMap"> select * from user where id = #{id}; </select> </mapper>
-
编写测试文件,每个Mybatis应用都是以SqlSessionFactory的实例为核心的,首先将配置文件通过输入流读取,SqlSessionFactoryBuilder从配置中构建出SqlSessionFactory实例,在获取到Factory对象后创建出SqlSession实例,通过SqlSession对象的映射器方法获取对应的实体类并执行操作,最后释放资源。
//1.读取配置文件 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建SqlSessionFactory工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.使用工厂生产SqlSession对象 SqlSession session = factory.openSession(); //4.使用SqlSession对象创建Dao接口的代理对象 UserMapper userMapper = session.getMapper(UserMapper.class); //5.使用代理对象执行方法 List<User> users = userMapper.findAll(); for (User user : users) { System.out.println(user); } //6.释放资源 session.close(); in.close();
SqlSession 在 MyBatis 中是非常强大的一个类。它包含了所有执行语句、提交或回滚事务以及获取映射器实例的方法。
总结:
- 获取配置文件的方式
- 使用类加载器,这种只能读取类路径的配置文件
- 使用ServletContext对象的getRealPath()方法
- SqlSessionFactory工厂模式的优势在于:
- 避免了使用new创建新对象,解耦(降低类之间的依赖关系)。
- SqlSessionFactoryBuilder创建者模式:
- 把对象的创建细节隐藏,使使用者直接调用方法即可拿到复杂对象。
- session.getMapper(UserMapper.class);使用代理模式
- 使用另一个类实现并增强一个类的功能。
- ⭐️getMapper方法的本质:使用Proxy.newProxyInstance()方法生成代理对象MapperProxy类,该类最终会生成一个MappedMethod对象,然后执行其execute()方法,将当前的sqlSession和方法参数传入执行sql,最终还是调用了sqlSession相应的方法进行的查询,比如说最常用的返回多个值就是调用了sqlSession的selectList()方法完成查询。
- 获取配置文件的方式
-
注意事项
- 映射文件的目录需要和对应的Dao接口的包结构相同。
- 映射文件中mapper标签的namespace属性的取值为对应Dao接口的全限定类名。
- 映射文件中操作配置标签(select)的id属性的取值为Dao接口的方法名。
- 映射文件中操作配置标签的resultType属性,表示返回的封装对象的类型。
-
⭐️Dao接口的原理
-
Dao接口,Mapper接口,接口的全限名,就是映射⽂件中的namespace的值,接口的⽅法名,就是映射⽂件中对应操作标签(如select)的id值,接口⽅法内的参数,就是传递给sql的参数。
-
Mapper接口是没有实现类的,当调⽤接口⽅法时,接口全限名+⽅法名拼接字符串作为key值,可唯⼀定位⼀个操作标签(select,insert,update,delete等)。
-
Dao接口⾥的⽅法,是不能重载的,因为是全限名+⽅法名的保存和寻找策略。
Dao接口的⼯作原理是JDK动态代理,Mybatis运⾏时会使⽤JDK动态代理为Dao接口⽣成代理proxy对象,代理对象proxy会拦截接口⽅法,转⽽执⾏映射文件中的sql,然后将sql执⾏结果返回。
-
-
使用注解配置MyBatis
-
在持久层实体类中添加注解
public interface UserDao { /** * 查询所有记录 * * @return */ @Select("select * from user") List<User> findAll(); }
-
删除实体类对应的xml文件,在主配置文件中的mapper标签设置class属性,代表映射位置,值为对应实体类的全限定类名。
<mappers> <mapper class="cn.sucrelt.dao.UserDao"/> </mappers>
-
¶基本CURD中的注意事项
-
将测试文件进行功能分离,利用单元测试的
@Before
和@After
注解,在测试前执行相关初始化生成Session对象的操作,在测试之后,执行事务提交session.commit()
以及关闭连接释放资源的操作。 -
在执行数据库操作时如果需要保存相关信息:
<!--保存用户--> <insert id="saveUser" parameterType="cn.sucrelt.domain.User"> <!-- 配置保存时获取插入的id --> <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER"> select last_insert_id(); </selectKey> insert into user(username, birthday, sex, address) values (#{username}, #{birthday}, #{sex}, #{address}); </insert>
其中,keyColumn为数据库的列名,keyProperty为实体类对应的属性名,order表示在该数据库操作执行之后获取该值。
-
在sql语句中使用
#{}
字符代表占位符,相当于jdbc中的?
,用于具体执行语句时替换实际的参数。- #{}中的内容,使用的是OGNL表达式, 它是apache提供的一种表达式语言,全称是:Object Graphic Navigation Language,即对象图导航语言,是按照一定的语法格式来获取数据的。
- 语法格式: #{对象.对象}。
- #{}中的名称要和实体类中getter/setter方法一致,如果是默认生成的,则与实体类的属性名一致。
- 如果sql语句中只含有一个占位符表示变量,则变量名任意都可以。
-
模糊查询时,由于映射文件中不使用%:
-
在测试传参时加入%,实际上是对参数进行字符串的拼接
<!--根据name模糊查询用户--> <select id="findByName" parameterType="String" resultType="cn.sucrelt.domain.User"> select * from user where username like #{username}; </select>
/** * 测试模糊查询 */ @Test public void testFindByName() throws IOException { //使用代理对象执行方法 List<User> users = userMapper.findByName("%王%"); for (User user : users) { System.out.println(user); } }
-
使用
${value}
代替原来的占位符#{}
<!--根据name模糊查询用户--> <select id="findByName" parameterType="String" resultType="cn.sucrelt.domain.User"> select * from user where username like '%${value}%'; </select>
/** * 测试模糊查询 */ @Test public void testFindByName() throws IOException { //使用代理对象执行方法 List<User> users = userMapper.findByName("王"); for (User user : users) { System.out.println(user); } }
-
#{}与${}的区别
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,可以有效防止sql注入。#{}可以接收简单类型值或pojo属性值。
${}表示拼接sql串,通过${}可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值。
-
-
parameterType属性的取值可以是基本类型,引用类型(例如:String类型),还可以是实体类类型(POJO类),也可以使用实体类的包装类。当是实体类的包装类时,使用OGNL表达式的语法获取查询条件进行查询。一定要写全限定类名。
<!-- 根据用户名称模糊查询,参数变成一个QueryVo对象了 --> <select id="findByVo" resultType="cn.sucrelt.domain.User" parameterType="cn.sucrelt.domain.QueryVo"> select * from user where username like #{user.username}; </select>
#{user.username}它会先去找user对象(前提是对应类QueryVo中存在getUser方法),然后在user对象中找到username属性,并调用getUsername()方法把值取出来。但是我们在parameterType属性上指定了实体类名称,所以可以省略user.而直接写username。
-
resultType属性可以指定结果集的类型,它支持基本类型和实体类类型。
-
resultMap结果集映射:当实体类中的属性名和数据库中的列名不一致时,可以使用resultMap做属性名的映射。
<resultMap type="cn.sucrelt.domain.User" id="userMap"> <!--主键字段的对应--> <id column="id" property="userId"/> <!--非主键字段的对应--> <result column="username" property="userName"/> <result column="sex" property="userSex"/> <result column="address" property="userAddress"/> <result column="birthday" property="userBirthday"/> </resultMap> <!--查询所有--> <select id="findAll" resultMap="userMap"> select * from user; </select>
- resultType和resultMap只能同时使用一个。
- resultMap的映射仅限于在结果集中。在sql拼接中,如#{}中的变量名,应当与实体类中属性名一致,不受该映射关系影响。
¶连接池
¶连接池特点
- 连接池是用于存储连接的容器
- 容器其实是一个集合对象,需要保证是线程安全的,不允许两个线程拿到一个连接
- 连接池必须实现队列的特性:先进先出
¶MyBatis中的连接池
-
MyBatis提供三种方式的配置
-
配置位置:主配置文件SqlMapConfig的dataSource标签中
<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>
-
type属性的取值:
- POLLED 采用传统的javax.sql.DataSource中的连接池
- UNPOOLED 采用传统的获取连接的方式,实现了javax.sql.DataSource中的接口,但没有使用池的思想
- JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象
-
-
MyBatis内部分别定义了实现了java.sql.DataSource接口的UnpooledDataSource,PooledDataSource类来表示UNPOOLED、POOLED类型的数据源。MyBatis在初始化时,根据
的type属性来创建相应类型的的数据源DataSource,即: - type=”POOLED”:MyBatis会创建PooledDataSource实例
- type=”UNPOOLED” : MyBatis会创建UnpooledDataSource实例
- type=”JNDI”:MyBatis会从JNDI服务上查找DataSource实例,然后返回使用
¶事务
在MyBatis中提交事务,实际上就是调用JDBC的setAutoCommit()
来实现事务控制。
- 在CUD的操作中,需要对事务进行提交,由于SqlSession对象在从连接池获取连接时,都会执行
connection.setAutoCommit(false)
方法,因此事务的提交需要手动进行,使用sqlSession.commit()
方法,相当于使用了JDBC中的connection.commit()
方法实现事务提交。 - 在调用factory对象的
openSession()
方法时,可以使用session = factory.openSession(true)
,这样就可以设置该SqlSession对象中的事务全部为自动提交,不需要手动执行sqlSession.commit()
方法。
¶动态Sql
-
if标签(注意使用where1=1)
<select id="findUserByCondition" resultMap="userMap" parameterType="cn.sucrelt.domain.User"> select * from user1 where 1=1 <if test="userName!=null"> and username = #{userName} </if> <if test="userSex!=null"> and sex = #{userSex} </if> </select>
-
where标签(无需使用where1=1)
<select id="findUserByCondition" resultMap="userMap" parameterType="cn.sucrelt.domain.User"> select * from user1 <where> <if test="userName!=null"> and username = #{userName} </if> <if test="userSex!=null"> and sex = #{userSex} </if> </where> </select>
-
foreach标签
<select id="findUserByIds" resultMap="userMap" parameterType="cn.sucrelt.domain.QueryVo"> select * from user1 <where> <if test="ids!=null and ids.size()>0"> <foreach collection="ids" open="and id in (" close=")" item="id" separator=","> #{id} </foreach> </if> </where> </select>
foreach标签中,collection表示遍历的集合,open表示拼接到sql语句中开始的部分,close表示结束的部分,separator表示中间分隔符,item表示遍历到的每个元素,在标签体中#{}中的内容与item一致。
¶多表查询
¶一对一查询
查询要求:查询Account表和User表中的信息,Account表中存在外键UID对应User表中的主键id,此时查询的结果集包含Account表和User表中的部分信息。
SELECT account.*, user.username, user.address
FROM account,
user
WHERE user.id = account.UID
该一对一多表查询的结果集需要另作处理。
-
通过扩展从表实体类封装结果集
新建一个类AccountUser,继承Account类并扩展,在其中加入对应User表中的属性username和address,执行SQl时的结果集设置为该类即可。
即定义专门的po类作为输出类型,其中定义了sql查询结果集所有的字段。此方法较为简单,企业中使用普遍。
<select id="findAllAccount" resultType="cn.sucrelt.domain.AccountUser"> SELECT account.*, user.username, user.address FROM account, user WHERE user.id = account.UID </select>
-
通过resultMap,定义专门的resultMap用于映射一对一查询结果。
在Account从表实体类中包含一个主表实体User的对象引用,并生成对应的getter和setter方法。
public class Account implements Serializable { private Integer id; private Integer uid; private Double money; /** * 从表实体包含一个主表实体的对象引用 */ private User user; ...
定义一个resultMap,设置Account表与实体类的映射关系,这里将表中的id设置为aid用于区分user表中的id。然后使用
association
标签将User表及其对应的实体类属性做映射。注意:在sql语句的编写中,查询User表所有信息(
u.*
),以及Account表中的所有信息,其中将a.id
设置为aid
。<!--定义封装Account和User的resultMap--> <resultMap id="accountUserMap" type="cn.sucrelt.domain.Account"> <id column="aid" property="id"/> <result column="uid" property="uid"/> <result column="money" property="money"/> <!-- 它是用于指定从表方的引用实体属性 --> <association property="user" javaType="cn.sucrelt.domain.User"> <id column="id" property="userId"/> <result column="username" property="userName"/> <result column="sex" property="userSex"/> <result column="birthday" property="userBirthday"/> <result column="address" property="userAddress"/> </association> </resultMap> <!--查询所有账户,同时包含用户名和地址,第二种方式--> <select id="findAllAccount2" resultMap="accountUserMap"> select u.*, a.id as aid, a.uid, a.money from account a, user u where u.id = a.uid </select>
¶一对多查询
查询user表中的每个用户信息以及用户包含的所有账户信息
select u.*, a.id as aid, a.uid, a.money
from user u
left outer join account a on u.id = a.uid
在主表User对应的实体类User中加入从表实体类Account的集合引用
public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
//一对多关系映射。主表实体应该包含从表实体的集合引用
private List<Account> accounts;
...
定义resultMap用于封装结果集,对应加入Account集合引用的User实体类
<!--定义加入Account集合的User对象的resultMap-->
<resultMap id="userAccountMap" type="cn.sucrelt.domain.User">
<id property="userId" column="id"></id>
<result column="username" property="userName"/>
<result column="address" property="userAddress"/>
<result column="sex" property="userSex"/>
<result column="birthday" property="userBirthday"/>
<!-- collection是用于建立一对多中集合属性的对应关系 property为主表对应实体类中的属性 ofType用于指定集合元素的数据类型 -->
<collection property="accounts" ofType="cn.sucrelt.domain.Account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<!-- 根据用户查询所有账户 -->
<select id="findAllAccountByUser" resultMap="userAccountMap">
select u.*, a.id as aid, a.uid, a.money
from user u
left outer join account a on u.id = a.uid
</select>
¶多对多查询
在数据库中要让表具有多对多的关系,需要使用中间表
查询身份表role中所有信息,对应user表中的用户信息,中间表为user_role
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
在role实体类中,加入多对多关系映射
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
//多对多的关系映射
private List<User> users;
...
使用封装的结果集执行sql
<!--定义role表的ResultMap-->
<resultMap id="roleMap" type="cn.sucrelt.domain.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="cn.sucrelt.domain.User">
<id column="id" property="userId"></id>
<result column="username" property="userName"></result>
<result column="address" property="userAddress"></result>
<result column="sex" property="userSex"></result>
<result column="birthday" property="userBirthday"></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>
查询的结果将会返回结果集roleMap类型的数据,对应于包含User实体类的Role实体类对象。
同理,可以查询用户表User中每个用户所对应的身份表Role中的信息,实现User表和Role的多对多查询操作。
¶延迟加载
-
延迟加载:为了提高数据库的查询性能,尽量使用单表查询,如果需要关联数据时才进行多表联合查询。
一对多,多对多:一般采用延迟加载;
一对一,多对一:一般采用立即加载。
-
在配置文件SqlMapConfig.xml中设置延迟加载参数
- lazyLoadingEnabled:如果为false,则所有相关联的都会被初始化加载;
- aggressiveLazyLoading:如果为true,
<!-- 全局配置参数 --> <settings> <!-- 延迟加载总开关 --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 设置按需加载 --> <setting name="aggressiveLazyLoading" value="false" /> </settings>
-
使用association实现:查询账户信息,并查询对应的用户信息
-
根据之前的方式,使用resultMap配置结果集,在其中使用association标签配置延迟查询
<!--定义封装Account和User的resultMap--> <resultMap id="accountUserMap" type="cn.sucrelt.domain.Account"> <id column="aid" property="id"/> <result column="uid" property="uid"/> <result column="money" property="money"/> <!-- 配置延迟加载 --> <association property="user" javaType="cn.sucrelt.domain.User" select="cn.sucrelt.dao.UserMapper.findUserById" column="uid"> </association> </resultMap> <select id="findAll" resultMap="accountMap"> select * from account </select>
select属性:指定当需要延迟加载时执行的select映射位置,此处为查询用户的唯一标识。
column属性:执行select属性中的的查询所需的参数,对应为uid,即account中查询出来的uid值,延迟加载时根据此值去user表中查询。
-
在user表对应的映射文件中设置findUserById
<mapper namespace="cn.sucrelt.dao.UserMapper"> <!-- 根据id查询 --> <select id="findUserById" resultType="cn.sucrelt.domain.User" parameterType="int" > select * from user where id = #{uid} </select> </mapper>
-
在测试结果时
@Test public void testFindAll() { //6.执行操作 List<Account> accounts = accountDao.findAll(); System.out.println(accounts.get(0).getUser()); }
因为使用了延迟加载,所以只查询所有时并不会显示user信息,当获取user信息是才会进行延迟加载显示user信息。
-
-
使用collection实现:查询用户信息,并查询对应的所有账户信息
-
使用collection标签的配置如下:
<resultMap id="userAccountMap" type="cn.sucrelt.domain.User"> <id property="userId" column="id"></id> <result column="username" property="userName"/> <result column="address" property="userAddress"/> <result column="sex" property="userSex"/> <result column="birthday" property="userBirthday"/> <collection property="accounts" ofType="cn.sucrelt.domain.Account" select="cn.sucrelt.dao.AccountMapper.findByUid" column="id"> </collection> </resultMap> <select id="findAll" resultMap="userMap"> select * from user </select>
- select属性: 用于指定查询account列表的sql语句,所以填写的是该sql映射的id
- column属性: 用于指定select属性的sql语句的参数来源,上面的参数来自于user的id列,所以就写成id这一个字段名了
-
account对应配置文件中
<!-- 根据用户id查询账户信息 --> <select id="findByUid" resultType="account" parameterType="int"> select * from account where uid = #{uid} </select>
-
在执行查询用户信息时,只有执行了user对象的getAccount()方法,才会延迟加载显示account信息。
-
¶缓存
¶一级缓存
- 一级缓存是SqlSession范围的缓存,如执行了查询某一user对象,再次查询时将会在缓存中查询,当调用SqlSession的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。
- sqlSession.clearCache();//此方法也可以清空缓存。
¶二级缓存
-
二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
-
第一步:在SqlMapConfig.xml文件开启二级缓存
<settings> <!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> </settings>
-
第二步:配置相关的Mapper映射文件
<cache>标签表示当前这个mapper映射将使用二级缓存,区分的标准就看mapper的namespace值。 <?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.sucrelt.dao.UserMapper"> <!-- 开启二级缓存的支持 --> <cache></cache> </mapper>
-
第三步:配置statement上面的useCache属性
<!-- 根据id查询 --> <select id="findById" resultType="user" parameterType="int" useCache="true"> select * from user where id = #{uid} </select>
将UserDao.xml映射文件中的
注意:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
-
使用二级缓存时,所缓存的类一定要实现java.io.Serializable接口,这种就可以使用序列化方式来保存对象。
¶注解开发
Mybatis也可以使用注解开发方式,这样可以减少编写Mapper映射文件。
常用注解如下:
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result一起使用,封装多个结果集
@ResultMap:实现引用@Results定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态SQL映射
@CacheNamespace:实现注解二级缓存的使用
例如,在UserMapper中使用注解设置查询所有用户的方法如下,如此不需要使用xml对该类进行映射。
/**
* 查询所有用户
* @return
*/
@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 = "cn.sucrelt.dao.AccountMapper.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();