一、环境搭建
详情见入门篇1
额外:
在配置主配置文件时,在Mapper的配置中可以使用package直接将dao包下的所有mapper打包注册,不用一个一个注册。
<mappers> <package name="com.Yu.dao"/> </mappers>
二、单表CRUD操作(代理dao方式)
mybatis一共有四种注解分别为:
@Select @Insert @Update @Delete在注解后就可以添加sql语句的操作
1、实例
在配置好的情况下CRUD操作如下所示:
1.dao类
public interface IUserDao {
//查询所有用户
@Select("select * from user")
List<User> findAll();
//保存用户
@Insert("insert into user(username,address,sex,birthday)" +
"values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
//更新用户
@Update("update user set username=#{username}," +
"sex=#{sex},birthday=#{birthday},address=#{address} " +
"where id=#{id}")
void updateUser(User user);
//删除用户
@Delete("delete from user where id=#{id}")
void deleteUser(Integer userId);
//根据id查询用户
@Select("select * from user where id=#{id}")
User findById(Integer userId);
//根据用户名称模糊查询
@Select("select * from user where username like #{username}")
List<User> findUsernameByName(String username);
//查询总用户数量
@Select("select count(*) from user")
int findTotal();
}
2、对应测试操作
其中Before,和After注解完成 配置读取、SqlSessionFactroyBuilder、SqlSessionFactroy、和SqlSession,进而动态代理原方法的过程。
public class AnnoCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
@Before
public void init() throws IOException {
in= Resources.getResourceAsStream("SqlMapConfig.xml");
factory=new SqlSessionFactoryBuilder().build(in);
session =factory.openSession();
userDao = session.getMapper(IUserDao.class);
}
@After
public void destory() throws IOException {
session.commit();
session.close();
in.close();
}
@Test
public void testSave(){
for (int i = 0; i < 20; i++) {
User user = new User();
user.setSex("男");
user.setAdress("测试的");
user.setUsername("胡无缺");
userDao.saveUser(user);
}
}
@Test
public void testUpdate(){
User user = new User();
user.setId(1);
user.setUsername("SCCC");
user.setAdress("earth");
user.setSex("女");
user.setBirthday(new Date());
userDao.updateUser(user);
}
@Test
public void testDelete(){
userDao.deleteUser(1);
}
@Test
public void testFindOne(){
User user = userDao.findById(2);
System.out.println(user);
}
@Test
public void testFindByname(){
List<User> users = userDao.findUsernameByName("%胡%");
for (User user:users) {
System.out.println(user);
}
}
@Test
public void testFindTotal(){
int count = userDao.findTotal();
System.out.println(count);
}
}
2、结果集的对应(@Results() @ResultMap())
如果数据库表与实体类属性名称不对应怎么办?
答:可以使用@Results()注解一一对应,传入colmn代表数据库中的列名称,property代表实体类属性。
假设此时User对象的属性为userId,userName,userAddress,userSex,userBirthday而数据库user表中是id,username,address,sex,birthday。
@Select("select * from user") //随便取的id
@Results(id="userMap",value={
//为true表示为增值主键
@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();
当下一个出现需要对应的方法时,只需要添加@ResultMap(value={“userMap”})
如:
//查询所有用户
@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查询用户
@Select("select * from user where id=#{id}")
@ResultMap(value = "userMap")
User findById(Integer userId);
三、多表查询操作
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
}
假设新加了一个Account类,代表账户,它由id(主键),uid(userID),money,User对象,组成。
多个账户对应一个用户,这是多对一的关系,但Mybatis并没有这种,只有一对一关系,一对一也可以来实现多对多的关系。
一个用户有多个账户,这是一对多的关系。
1.立即加载与延迟加载
-
延迟加载:在使用数据时才发起查询,不用的时候不查。通常在一对多,多对多的关系中使用。
-
立即加载:不管使用不使用数据,只要一调用方法,马上发起查询。通常在多对一,一对一的关系中使用。
2.多对一/一对一(立即加载)
一对一的关系体现在,需要查询一个账户所持有的用户(一个账户对应一个用户),用到了联表查询。在账户中,可以拿到其userId,所以只需要再通过IUserDao中的findById()就可以拿到该账户所归属的用户。
同样通过@Results注解来配置返回的联表查询结果。
先在dao包的IAccountDao接口中,写Account的findAll()方法
IAccountDao{
@Select("select * from account")
//封装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();
}
总结
总的来说最后一行@Result意思是 封装成user类,使用uid (column) ,是一对一关系 (one) ,去com.itheima.dao.IUserDao.findById查,使用立即加载 (fetchType)
3.一对多(延迟加载)
要想实现一对多那么User类要存在一个关系映射用来代表其拥有的账户,User实现类应如下
public class User implements Serializable {
private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;
//新加的
private List<Account> accounts;}
一对多的关系体现在一个用户拥有多个账户
通过调用IUserDao接口中的findAll()方法,希望查出所有的用户,及每个用户的所有账户。
因为要根据用户Id查账户,所以在IAccountDao中也要写一个抽象方法如下:
//根据用户id查询账户信息
@Select("select*from account where uid=#{userId}")
List<Account> findAccountByUid(Integer userId);
所以IUserDao中的findAll()变为如下:
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();
}
总结
总的来说,最后一行@Result表示,返回封装的是account类 (property) ,使用 id (column) 去com.itheima.dao.IAccountDao.findAccountByUid 查,是一个一对多的关系 (many) 。使用延迟加载 (fetchType = FetchType.LAZY) 。
四、缓存的配置
1.一级缓存
Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中;第二次以后是直接去缓存中取。
等于说只发起了一次查询
当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空。
2.二级缓存
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的 mapper映射文件内容,多个SqlSession共享。 Mybatis需要手动设置启动二级缓存。
通俗讲就是关闭一次Session,再发起Session。如果开启二级缓存,那么不会发起第二次查询请求。
配置步骤:
- 在主配置文件中写入
<settings>
<setting name = "cacheEnabled" value="true"/>
</settings>
- 在想进行二级缓存的dao上使用@CacheNamespace的注解
@CacheNamespace(blocking=true)
public interface IUserDao{
......
}