Last updated on 十月 11, 2020
这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。
mybatis 的常用注解说明
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
一、使用 Mybatis 注解实现基本 CRUD
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户
*/
@Select("select * from user")
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="address",property="userAddress"),
@Result(column="birthday",property="userBirthday")
})
List<User> findAll();
/**
* 根据id 查询一个用户
*/
@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);
/**
* 保存操作
*
* statement属性:填入将会被执行的 SQL 字符串数组。
* keyProperty属性:填入将会被更新的参数对象的属性的值。
* before属性:填入 true 或 false 以指明 SQL 语句应被在插入语句的之前还是之后执行。
* resultType属性:填入 keyProperty 的 Java 类型。
* statementType属性:填入Statement、 PreparedStatement 和 CallableStatement 中的 STATEMENT、 PREPARED 或 CALLABLE 中任一值填入 。默认值是 PREPARED。
*/
@Insert("insert into user(username,sex,birthday,address) values " +
"(#{userName},#{userSex},#{userBirthday},#{userAddress})")
/*
如果向数据库中插入一条数据,同时有希望返回该条记录的主键,该怎么处理了?有两种情况:
(1)数据库主键不是自增列,需要预先生成
(2)是自增列,插入之后才能获知
*/
@SelectKey(keyColumn ="id",
keyProperty = "userId",
resultType = Integer.class,
before = false,
statement = {"select last_insert_id()"})
int saveUser(User user);
/**
* 更新操作
*/
@Update("update user set username = #{userName},address=#{userAddress}," +
"sex=#{userSex},birthday=#{userBirthday} " +
"where id = #{userId} ")
int updateUser(User user);
/**
* 删除用户
*/
@Delete("delete from user where id = #{userId}")
int deleteUser(Integer userId);
/**
* 聚合函数
*/
@Select("select count(*) from user")
int findTotal();
/**
* 模糊查询
*/
@Select("select * from user where username like #{userName}")
List<User> findByName(String name);
}
//测试类
public class MybatisAnnotationCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession sqlSession;
private IUserDao userdao;
@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
sqlSession = factory.openSession();
userdao = sqlSession.getMapper(IUserDao.class);
}
@After
public void destroy() throws IOException {
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);
}
/**
* 测试保存
*/
@Test
public void testSave(){
User user = new User();
user.setUserName("mybatis annotation");
user.setUserSex("男");
user.setUserAddress("北京是顺义区");
user.setUserBirthday(new Date());
int res = userdao.saveUser(user);
System.out.println("影响数据库记录的行数:" + res);
System.out.println("插入的主键值:" + user.getUserId());
}
/**
* 测试更新
*/
@Test
public void testUpdate(){
User user = userdao.findById(45);
user.setUserBirthday(new Date());
user.setUserSex("女");
int res = userdao.updateUser(user);
System.out.println(res);
user = userdao.findById(45);
sqlSession.commit();
System.out.println(user);
}
/**
* 测试删除
*/
@Test
public void testDelete(){
int res = userdao.deleteUser(49);
System.out.println(res);
}
/**
* 测试查询使用聚合函数
*/
@Test
public void testFindTotal(){
int res = userdao.findTotal();
System.out.println(res);
}
/**
* 测试模糊查询
*/
@Test
public void testFindByName(){
List<User> users = userdao.findByName("%王%");
for (User user : users) {
System.out.println(user);
}
}
}
注解 复杂结构 分析:
@Results 注解
代替的是标签
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})或@Results(@Result())
@Resutl 注解
代替了 标签和标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
代替了标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
一对一 实现!
public interface IUserDao {
/**
* 查询所有用户
*/
@Select("select * from user")
@Results(id = "userMap",
value = {
@Result(id = true,column="id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "sex",property = "userSex"),
@Result(column = "address",property = "userAddress"),
@Result(column = "birthday",property = "userBirthday")
})
List<User> findAll();
/**
* 根据id查询一个用户
*/
@Select("select * from user where id = #{uid}")
@ResultMap("userMap")
User findById(Integer userId);
}
public interface IAccountDao {
/**
* 查询所有账户,采用延迟加载的方式,查询账户,所属用户
*/
/*
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
*/
@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(column = "uid",//子查询的参数
property = "user",//user 是account类中的 主表属性
one = @One(select = "com.itheima.dao.IUserDao.findById",
fetchType = FetchType.LAZY)
)
})
/*
@One 注解(一对一)
代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
*/
List<Account> findAll();
}
测试类
ublic class AccountTest {
private IAccountDao accountDao;
private SqlSession sqlSession;
private InputStream in;
@Before
public void init() throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.获取SqlSession对象
sqlSession = factory.openSession(true);
//4.获取dao的代理对象
accountDao = sqlSession.getMapper(IAccountDao.class);
}
@After
public void close(){
sqlSession.close();
}
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
// for (Account account : accounts) {
// System.out.println(account);
// System.out.println(account.getUser());
// }
}
开启了延迟加载
具体细节 都在代码注释上了!具体自己看!!
一对多实现!
public interface IUserDao {
/**
* 查询所有用户
*/
@Select("select * from user")
@Results(id = "userMap",
value = {
@Result(id = true,column="id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "sex",property = "userSex"),
@Result(column = "address",property = "userAddress"),
@Result(column = "birthday",property = "userBirthday"),
@Result(column = "id",//会传入的参数,从数据库获取
property = "accounts", //需要存入的属性
many=@Many(
select = "com.itheima.dao.IAccountDao.findByUid",
fetchType = FetchType.LAZY
)
)
})
/*
@Many:
相当于<collection>的配置
select 属性:代表将要执行的 sql 语句
fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值
*/
List<User> findAll();
/**
* 根据id查询一个用户
*/
@Select("select * from user where id = #{uid}")
@ResultMap("userMap")
User findById(Integer userId);
}
public interface IAccountDao {
/**
* 根据用户id 查询用户下i的所有账户
*/
@Select("select * from account where uid = #{uid}")
List<Account> findByUid(Integer userId);
}
public class AccountTest {
private IUserDao userDao;
private SqlSession sqlSession;
private InputStream in;
@Before
public void init() throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.获取SqlSession对象
sqlSession = factory.openSession(true);
//4.获取dao的代理对象
userDao = sqlSession.getMapper(IUserDao.class);
}
@After
public void close(){
sqlSession.close();
}
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
System.out.println(user.getAccounts());
}
}
最后温馨提示:一定要在 属性类中加入 需要配对的成员变量,不然映射不到的哦