mybatis的注解开发入门
mybatis注解开发:
这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。本次我们先围绕一些基本的 CRUD 来学习,再学习复杂映射关系及延迟加载。
mybatis常用注解说明:
前期准备工作:
使用IDEA软件制作:
新建Maven工程:
GroupID :是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构。
ArtifactID:是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。
点击下一步,然后点击完成,maven工程就建好了
并且在pom.xml导入对应的坐标
在resources下创建配置文件等信息:
编写SqlMapperConfig.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>
<!--导入外部文件-->
<properties resource="jdbcConfig.properties"></properties>
<!--给实体类取别名-->
<typeAliases>
<package name="com.itmei.domain"/>
</typeAliases>
<!--环境配置-->
<environments default="mysql">
<!--mysql环境-->
<environment id="mysql">
<!--事务选择-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源-->
<dataSource type="POOLED">
<!--数据库的基本信息-->
<property name="driver" value="${jdbc.driver}"/><!--这里的value要和外置文件的key一致-->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--注册接口的别名-->
<mappers>
<package name="com.itmei.dao"/>
</mappers>
</configuration>
编写jdbcConfig.properties:数据库的配置信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456
使用 Mybatis 注解实现基本 CRUD:
完成增删改查等操作:
创建User实体类
注意:这里我们故意使实体类的名称和数据库列名称不一样
使用注解方式开发持久层接口
我们先写2个查询方法,查询所有和查询一个用户信息:
其中里面的注解
@Select:查询的语句
@Results:各个属性的含义,id为当前结果集声明唯一标识,value值为结果集映射关系,@Result代表一个字段的映射关系,column指定数据库字段的名称,property指定实体类属性的名称,jdbcType数据库字段类型,@Result里的id值为true表明主键,默认false;使用@ResultMap来引用映射结果集,其中value可省略。
@Results相当于xml里面的< resultMap >标签
@ResultMap来引用映射结果集(一般使用在查询封装)
单个参数
可以接收基本类型,对象类型,集合类型,都可以接收,mybatis可以直接使用这个参数,不用经过任何处理,同时#{}这里面的名称可以随便写。
注解所有的开发:
package com.itmei.dao;
import com.itmei.domain.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserDao {
/**
* 查询所有
* @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"),
})
List<User> findAll();
/**
* 通过id查询一个用户
* @param id
* @return
*/
@Select("select * from user where id=#{uid}") /*这里单个参数可以随便填写*/
@ResultMap("userMap")
User findById(Integer id);
/**
* 保存用户
* @param user
* @return
*/
@Insert("insert into user (username,sex,birthday,address) values (#{userName},#{userSex},#{userBirthday},#{userAddress})")
@SelectKey(keyColumn = "id",keyProperty = "userId",before = false,resultType = Integer.class,
statement = {"select last_insert_id()"})/*返回用户id的信息*/
int saveUser(User user);
/**
* 用户的更新
* @param user
* @return
*/
@Update("update user set username=#{userName},sex=#{userSex},birthday=#{userBirthday},address=#{userAddress} where id=#{userId}")
User updateUser(User user);
/**
* 删除用户
* @param id
* @return
*/
@Delete("delete from user where id=#{userId}")
int deleteUser(Integer id);
/**
* 查询总的信息(聚合函数)
* @return
*/
@Select("select count(*) from user ")
int findTotal();
/**
* 模糊查询
* @param name
* @return
*/
@Select("select * from user where username like #{userName}")
@ResultMap("userMap")
List<User> findByName(String name);
/*这样我们就不要编写UserDao.xml映射文件*/
}
现在我们编写测试类:
UserTest测试类:
public class UserTest {
private InputStream in;
private SqlSession session;
private UserDao userDao;
@Before/*在测试执行之前运行*/
public void init() throws Exception{
//1.读取配置文件
in= Resources.getResourceAsStream("SqlMapperConfig.xml");
//2.创建工厂对象
SqlSessionFactory factory= new SqlSessionFactoryBuilder().build(in);
//3.创建SqlSession对象 并且更改为自动添加事务
session = factory.openSession(true);
//4.通过session对象创建dao的代理对象
userDao = session.getMapper(UserDao.class);
}
@After/*在测试执行之后运行*/
public void end() throws Exception{
//6.释放资源
session.close();
in.close();
}
}
所有的测试方法和代码:
package com.itmei.Test;
import com.itmei.dao.UserDao;
import com.itmei.domain.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class UserTest {
private InputStream in;
private SqlSession session;
private UserDao userDao;
@Before/*在测试执行之前运行*/
public void init() throws Exception{
//1.读取配置文件
in= Resources.getResourceAsStream("SqlMapperConfig.xml");
//2.创建工厂对象
SqlSessionFactory factory= new SqlSessionFactoryBuilder().build(in);
//3.创建SqlSession对象 并且更改为自动添加事务
session = factory.openSession(true);
//4.通过session对象创建dao的代理对象
userDao = session.getMapper(UserDao.class);
}
@After/*在测试执行之后运行*/
public void end() throws Exception{
//6.释放资源
session.close();
in.close();
}
/**
* 查询所有用户
*/
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for (User user:users){
System.out.println(user);
}
}
/**
* 查询一个用户
*/
@Test
public void testFindById(){
User user = userDao.findById(41);
System.out.println(user);
//结果:User{userId=41, userName='update user clear cache', userAddress='北京朝阳区', userSex='男', userBirthday=Tue Feb 27 17:47:08 CST 2018}
}
/**
* 保存用户
*/
@Test
public void testSaveUser(){
User user=new User();
user.setUserName("MJW");
user.setUserSex("男");
user.setUserAddress("北京");
user.setUserBirthday(new Date());
System.out.println("用户信息"+user);
//结果:用户信息User{userId=null, userName='MJW', userAddress='北京', userSex='男', userBirthday=Sun Jun 07 15:41:48 CST 2020}
userDao.saveUser(user);
System.out.println("用户信息"+user);
//结果:用户信息User{userId=69, userName='MJW', userAddress='北京', userSex='男', userBirthday=Sun Jun 07 15:41:48 CST 2020}
}
/**
* 更新用户,通过id
*/
@Test
public void testupdateUser(){
User user=new User();
user.setUserId(69);
user.setUserName("update");
user.setUserSex("男");
user.setUserAddress("北京");
user.setUserBirthday(new Date());
userDao.updateUser(user);
//调用方法查询用户
User u = userDao.findById(69);
System.out.println(u);
//结果:User{userId=69, userName='update', userAddress='北京', userSex='男', userBirthday=Sun Jun 07 15:48:14 CST 2020}
}
/**
* 删除一个用户
*/
@Test
public void testdelete(){
userDao.deleteUser(68);
}
/**
* 查询总记录数
*/
@Test
public void testFindTotal(){
int total = userDao.findTotal();
System.out.println("总记录数:"+total);
//总记录数:17
}
/**
* 模糊查询
*/
@Test
public void testFindByName(){
String name="%王%";
List<User> users = userDao.findByName(name);
for (User user:users){
System.out.println(user);
}
/*User{userId=42, userName='小二王', userAddress='北京金燕龙', userSex='女', userBirthday=Fri Mar 02 15:09:37 CST 2018}
User{userId=43, userName='小二王', userAddress='北京金燕龙', userSex='女', userBirthday=Sun Mar 04 11:34:34 CST 2018}
User{userId=46, userName='老王', userAddress='北京', userSex='男', userBirthday=Wed Mar 07 17:37:26 CST 2018}*/
}
}
使用注解实现复杂关系映射开发
实现复杂关系映射之前我们可以在映射文件中通过配置< resultMap>来实现,在使用注解开发时我们需要借助@Results 注解,@Result 注解,@One 注解,@Many 注解。
复杂关系映射的注解说明
使用注解实现 (一对一) 复杂关系映射及延迟加载
需求:
加载账户信息时并且加载该账户的用户信息,根据情况可实现延迟加载。(注解方式实现)
添加 User 实体类及 Account 实体类
User 实体类
package com.itheima.domain;
import java.io.Serializable;
import java.util.Date;
/**
* @author 黑马程序员
* @Company http://www.ithiema.com
*/
public class User implements Serializable{
private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public String getUserSex() {
return userSex;
}
public void setUserSex(String userSex) {
this.userSex = userSex;
}
public Date getUserBirthday() {
return userBirthday;
}
public void setUserBirthday(Date userBirthday) {
this.userBirthday = userBirthday;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAddress='" + userAddress + '\'' +
", userSex='" + userSex + '\'' +
", userBirthday=" + userBirthday +
'}';
}
}
Account 实体类
package com.itheima.domain;
import java.io.Serializable;
/**
* @author 黑马程序员
* @Company http://www.ithiema.com
*/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//多对一(mybatis中称之为一对一)的映射:一个账户只能属于一个用户
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
添加Account账户的持久层接口并使用注解配置
添加UserDao用户的持久层接口并使用注解配置
测试一对一关联及延迟加载
按正常道理当调用了findAll方法就会执行注解的所有数据,但是通过fetchType=FetchType.LAZY 实现延迟加载,在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。例如在进行一对多查询的时候,只查询出一方,当程序中需要多方的数据时,mybatis再发出sql语句进行查询,这样子延迟加载就可以的减少数据库压力。
使用注解实现 (一对多) 复杂关系映射
需求:
查询用户信息时,也要查询他的账户列表。使用注解方式实现。
分析:
一个用户具有多个账户信息,所以形成了用户(User)与账户(Account)之间的一对多关系。
3.3.3.1 User 实体类加入 List< Account>
3.3.3.2 编写用户的持久层接口并使用注解配置
3.3.3.3 编写账户的持久层接口并使用注解配置
3.3.3.4 添加测试方法
package com.itheima.test;
import com.itheima.dao.IUserDao;
import com.itheima.domain.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* @author 黑马程序员
* @Company http://www.ithiema.com
*/
public class UserTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
@Before//用于测试方法执行之前执行
public void init() throws Exception {
//1.读取配置,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory工厂
factory = new SqlSessionFactoryBuilder().build(in);
//3.获取SqlSession对象
session = factory.openSession(true);
//4.获取dao的代理对象
userDao = session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy() throws Exception {
//提交事务
session.commit();
//6.释放资源
session.close();
in.close();
}
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
// for(User account : users){
// System.out.println("----每个账户的信息-----");
// System.out.println(account);
// System.out.println(account.getAccounts());
// }
}
}
运行结果:因为使用延迟加载,如果使for循环可以使用那么会调用方法查询用户的信息,简称按需加载。
mybatis 基于注解的二级缓存
在 SqlMapConfig 中开启二级缓存支持
** 在持久层接口中使用注解配置二级缓存**