一、基于注解的开发环境搭建以及实现查询所有
1.定义主配置文件
mybatis的注解开发是对于映射配置文件这个层面来说的,所以仍然需要定义主配置文件,和前文基于xml配置方法和细节,和注意事项完全一致
<configuration>
<properties resource="jdbcConfig.properties">
</properties>
<!--使用typeAliases配置别名,它只能配置domain(实体类)中类的别名 -->
<typeAliases>
<!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写
用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
<package name="com.xpt.domain"/>
</typeAliases>
<!--配置环境 default 和 id保持一致-->
<environments default="mysql">
<environment id="mysql">
<!--配置事务类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源信息-->
<dataSource type="UNPOOLED">
<!--连接数据库的四个基本信息-->
<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>
</environment>
</environments>
<!--映射文件的位置-->
<mappers>
<!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了 -->
<!--指定带有注解的dao接口所在位置-->
<package name="com.xpt.dao"/>
</mappers>
</configuration>
2.准备实体类和Dao接口
和前文使用的数据表,实体类保持一致
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190927162550145.png)
3.Dao接口定义findAll方法,以及添加注解
// @Select(value = "select * from user")
//只有一个参数时,value可以省略
@Select("select * from user")
List<User> findAll();
4.测试类定义方法测试
public static void main(String[] args) throws Exception {
//1.获取字节输入流
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.根据字节输入流构建 SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.利用factory生产一个SqlSession
SqlSession sqlSession = factory.openSession();
//4.利用sqlSession获取代理对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
//5.利用代理对象 执行方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
//6.释放资源
sqlSession.close();
in.close();
}
- 结果:
- 上述就是基于注解开发的一个基本步骤
- 下面 关注一些细节的问题
5.注解开发和基于xml的映射配置文件开发对比
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190927163916460.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZhdF9jYWlfbmlhbw==,size_16,color_FFFFFF,t_70)
6.注解开发的一个小细节
- 只要使用的注解,就不能再建立对应的目录结构下建立
IUserDao.xml
配置文件了
- 不然会报错
二、基于注解开发的单表的CRUD
理解了前面的查询的过程,后面的内容都基本一致。
1.IUserDao
的配置代码
@Select("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
@Select("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
void updateUser(User user);
@Select("delete from user where id=#{id}")
void deleteUser(Integer userId);
2.测试类的代码
public class AnnotationCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession sqlSession;
private IUserDao userDao;
@Before
public void init() throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
sqlSession = factory.openSession();
userDao = sqlSession.getMapper(IUserDao.class);
}
@After
public void destroy() throws Exception{
sqlSession.commit();
sqlSession.close();
in.close();
}
@Test
public void testSave(){
User user = new User();
user.setUsername("mybatis annotation");
user.setAddress("唐人街");
userDao.saveUser(user);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(63);
user.setUsername("update mybatis annotation");
user.setAddress("唐人街 50号");
userDao.updateUser(user);
}
@Test
public void testDelete(){
userDao.deleteUser(63);
}
}
三、基于注解开发的单表查询的其他常用功能
1.IUserDao
的配置代码
@Select("select * from user where id = #{id}")
User findById(Integer userId);
@Select("select * from user where username like '%${value}%' ")
List<User> findUserByName(String username);
@Select("select count(*) from user ")
int findTotalUser();
2.测试类的代码
@Test
public void testFindById(){
User user = userDao.findById(57);
System.out.println(user);
}
@Test
public void testFindByName(){
// List<User> users = userDao.findUserByName("%mybatis%");
List<User> users = userDao.findUserByName("mybatis");
for(User user : users){
System.out.println(user);
}
}
@Test
public void testFindTotal(){
int total = userDao.findTotalUser();
System.out.println(total);
}
四、使用注解实现复杂关系映射开发
1.当实体类的属性名和数据表的字段名不一致的解决方案
在基于xml的配置开发的时候,二者不一致的时候,使用的是一个map来解决,注解开发如何解决这个问题呢?
1.1先修改实体类的属性名,重新生成相关方法
1.2使用@Results和@Result这两个注解
@Select("select * from user")
@Results(value = {
//id默认为false 这里指定为true是因为id为主键 column 数据表字段名 property 实体类属性名
@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();
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
- 3.结果:可以实现正常的结果
- 4.测试testFindById()
方法
@Test
public void testFindById(){
User user = userDao.findById(57);
System.out.println(user);
}
- 结果:没有封装成功,由于win10下mysql忽略大小写的缘故,显示了username
- 至于原因很简单,就是因为没有在该方法中进行相应的配置,那么问题来了,不可能每一个方法上都用那么大一串注解吧,
- 所以基于注解的方式也可以使用userMap来完成一次定义,多处使用的效果
2.定义注解的时候,添加id属性值
- 此时再测试findById()
方法:就可以成功完成查询
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190927191342283.png)
3.注解开发实现多对一(一对一)的查询配置
这里同样使用用户和账户的实例来说明
3.1首选在账户实体类中建立映射属性
//建立多对一(mybatis中称为 一对一)的映射 一个账户只能属于一个用户
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
3.2IAccountDao的注解配置
/**
* 查询account的信息 并同时查询所属的用户信息
* @return
*/
@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"),
//下面把user的信息也封装进来
@Result(
property = "user",
column = "uid",//在user表中当然是使用uid进行查询
//使用注解 @one 来指定一对一的关系 select是在user表中查询的全限定名加方法名
//后面 fetchType指定加载类型 LAZY延迟加载 EAGER立即加载
one = @One(select = "com.xpt.dao.IUserDao.findById",fetchType = FetchType.EAGER)
)}
)
List<Account> findAll();
- 注意点:
4.注解开发实现一对多
查询用户,并查询出用户下所有的账户信息
4.1实体类User中定义关系映射
//一对多关系映射 一个用户下 有多个账户
List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
4.2IUserDao完善注解配置
/**
* 查询所有用户 并同时查询对应的账户信息
* @return
*/
// @Select(value = "select * from user")
//只有一个参数时,value可以省略
@Select("select * from user")
@Results(id = "userMap",value = {
//id默认为false 这里指定为true是因为id为主键 column 数据表字段名 property 实体类属性名
@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",//查询结果 封装到accounts属性
column = "id",//这里的id就是用户id
many = @Many(select = "com.xpt.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY)
)
})
List<User> findAll();
4.3测试:
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for(User user : users){
System.out.println("---用户查询信息---");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
- 结果:
五、基于注解开发的二级缓存设置
1.一级缓存都是默认开启的
@Test
public void testFindById(){
User user1 = userDao.findById(42);
System.out.println(user1);
User user2 = userDao.findById(42);
System.out.println(user2);
System.out.println(user1 == user2);
}
- 结果:
2二级缓存配置
2.1主配置文件开启全局二级缓存
<!--配置开启二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2.2IUserDao开启二级缓存配置
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019092719555529.png)
2.3测试方法
public class SecondLevelCacheTest {
private InputStream in;
private SqlSessionFactory factory;
// private SqlSession sqlSession;
// private IUserDao userDao;
@Before
public void init() throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
// sqlSession = factory.openSession();
// userDao = sqlSession.getMapper(IUserDao.class);
}
@After
public void destroy() throws Exception{
// sqlSession.commit();
// sqlSession.close();
in.close();
}
@Test
public void testFindById(){
SqlSession sqlSession = factory.openSession();
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
User user1 = userDao.findById(42);
System.out.println(user1);
//释放一级缓存
sqlSession.close();
//再次打开缓存
SqlSession sqlSession1 = factory.openSession();
IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
User user2 = userDao1.findById(42);
System.out.println(user2);
sqlSession1.close();
System.out.println(user1 == user2);
}
2.4结果
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190927195502149.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZhdF9jYWlfbmlhbw==,size_16,color_FFFFFF,t_70)