MyBatis小记_three
目录
5.上面还只是一个单表查询的测试,下来我们要进行多表查询,查询一个账户所对应的用户信息
2.在账户的接口中提供一个方法,以便查询该用户对应的账户时,使用
注解开发
@Insert:实现新增 @Update:实现更新 @Delete:实现删除 @Select:实现查询 @Result:实现结果集封装 @Results:可以与@Result 一起使用,封装多个结果集 @ResultMap:实现引用@Results 定义的封装 @One:实现一对一结果集封装 @Many:实现一对多结果集封装 @SelectProvider: 实现动态 SQL 映射
环境搭建
1.创建Maven工程
1.在pom.xml中 引入以下jar包 <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
2.创建实体类
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
//get set 方法略 自己补上
}
3.提供接口,并提供增删改查的方法
public interface IUserDao {
//查询所有的方法
List<User> findAll();
//保存用户的方法
void saveUser(User user);
//更新用户
void updateUser(User user);
//删除一个用户
void deleteUser(Integer id);
//根据id查询出一个用户
User selectUserById(Integer id);
//根据姓名模糊查询
List<User> selectUserByName(String name);
//查询所有用户的个数
int selectAllUser();
}
4.编写SqlMapConfig.xml 主配置文件
<configuration>
<!--properties 用来加载外部的jdbc的配置文件 -->
<properties resource="jdbcConfig.properties"/>
<typeAliases>
<!--给该包下所有的类,都起别名,别名可以是类名的小写,大写-->
<package name="org.westos.domain"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源(连接池)-->
<dataSource type="POOLED">
<!-- 需要用${jdbc配置文件中的键名}-->
<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 name="org.westos.dao"/>
</mappers>
</configuration>
5.采用注解的方式,来进行增删改查
1.在接口的查询所有方法上添加 @select 注解
public interface IUserDao {
//查询所有的方法
@Select(value = "select * from user")
List<User> findAll();
}
6.测试
@Test
public void testFindAll() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
IUserDao dao = sqlSession.getMapper(IUserDao.class);
List<User> list = dao.findAll();
for (User user : list) {
System.out.println(user);
}
}
7.测试保存用户的方法
1.在接口中的保存用户方法上面,添加 @insert 注解
public interface IUserDao {
//保存用户的方法
@Insert(value = "insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
void saveUser(User user);
}
2. 测试
@Test
public void test() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
IUserDao dao = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setUsername("金城武");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("陕西西安");
dao.saveUser(user);
//提交事务
sqlSession.commit();
in.close();
sqlSession.close();
8.测试更新用户
1.在接口中的更新用户方法上添加 @Update 的注解
public interface IUserDao {
//更新用户
@Update("update user set username=#{username},address=#{address} where id=#{id}")
void updateUser(User user);
}
@Test
public void test() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
IUserDao dao = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setId(66);
user.setUsername("金巧巧");
user.setAddress("陕西咸阳");
dao.updateUser(user);
//提交事务
sqlSession.commit();
in.close();
sqlSession.close();
}
9.测试删除一个用户
1.在接口中的方法上 添加@Delete注解
//删除一个用户
@Delete("delete from user where id=#{id}")
void deleteUser(Integer id);
2.测试:
IUserDao dao = sqlSession.getMapper(IUserDao.class);
dao.deleteUser(66);
//提交事务
sqlSession.commit();
10.根据id查询一个用户
1.在接口中的方法上,添加注解
//根据id查询出一个用户
@Select(value = "select * from user where id=#{uid}")
User selectUserById(Integer id);
2.测试
IUserDao dao = sqlSession.getMapper(IUserDao.class);
User user = dao.selectUserById(66);
System.out.println(user);
//提交事务
sqlSession.commit();
11.根据姓名模糊查询
1.在接口的方法上添加注解
//根据姓名模糊查询
@Select(value = "select * from user where username like #{name}")
List<User> selectUserByName(String name);
2.测试
IUserDao dao = sqlSession.getMapper(IUserDao.class);
List<User> list = dao.selectUserByName("%沈%");
for (User user : list) {
System.out.println(user);
}
12.查询所有用户的个数
1.在接口的方法上添加注解 //查询所有用户的个数 @Select(value = "select count(*) from user") int selectAllUser(); 2.测试 IUserDao dao = sqlSession.getMapper(IUserDao.class); int i = dao.selectAllUser(); System.out.println(i);
当实体类的属性名和表中的字段名不一致时,采用注解怎么配置
1.修改实体类的属性名
public class User implements Serializable {
private Integer myid;
private String myusername;
private Date mybirthday;
private String mysex;
private String myaddress;
//get set 方法略 自己补上
}
说明:当我们实体类的属性名和表中字段名不一致后,我们查询用户时,就封装不到实体类当中了
那么我们就得进行配置
2.配置实体类的属性和表中字段的映射关系
1.我们就在接口中的查询所有方法上使用 @Results 注解 来配置 实体类属性名和表中字段名的映射关系,配好之后,我们查询所有用户,就可以封装进实体类中了
public interface IUserDao {
//查询所有的方法
@Select(value = "select * from user")
@Results(id = "userMap", value = {
//配置主键字段 id = true 表示这是主键字段
@Result(id = true, property = "myid", column = "id"),
//配置其他普通字段
@Result(property = "myusername", column = "username"),
@Result(property = "mybirthday", column = "birthday"),
@Result(property = "mysex", column = "sex"),
@Result(property = "myaddress", column = "address")
})
List<User> findAll();
}
2. 我们接口中还有一个根据id查询单个用户,也要将查询出的用户封装到实体类中,所以这个方法,也要配置 映射关系,但是,我们不是把上面配置好的映射关系,再复制一份,而是通过上面配置的 id名 引用一下即可,那么就使用 @ResultMap 来引用配置好的映射关系
//根据id查询出一个用户
@Select(value = "select * from user where id=#{uid}")
@ResultMap(value = "userMap") //引用上面配置好的映射关系
User selectUserById(Integer id);
使用注解进行多表查询
一对一的关系查询:比如查询该账户所对应的用户信息
1.提供账户的实体类
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//get set 方法略 自己补上
}
2.提供账户的接口
public interface IAccountDao {
//查询所有账户,以及该账户所对应的用户信息
List<Account> findAll();
}
3.给账户接口上的方法,添加注解,先查询出所有账户
public interface IAccountDao {
//查询所有账户,以及该账户所对应的用户信息
@Select("select * from account")
List<Account> findAll();
}
4.测试
public class TestAccount {
public static void main(String[] args) throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
IAccountDao dao = sqlSession.getMapper(IAccountDao.class);
List<Account> list = dao.findAll();
for (Account account : list) {
System.out.println(account);
}
in.close();
sqlSession.close();
}
}
5.上面还只是一个单表查询的测试,下来我们要进行多表查询,查询一个账户所对应的用户信息
1.用户表和账户表之间,他是一对多的关系,但是我们站在账户表角度看,那么一个账户就是属于一个用户,也就是说,多对一的关系,在MyBatis中看来就是一对一的关系
2.首先,在账户的实体类中,维护一个用户的对象,来描述这个一对一的关系
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//在多方维护一个一方的对象,来体现一对一的关系
private User user;
// get set 方法略 自己补上
}
6.在账户的接口中添加注解,来进行一对一的查询
1.我们先配置账户实体类和账户表的映射关系
2.再配置账户和用户的 一对一的关系
public interface IAccountDao {
//查询所有账户,以及该账户所对应的用户信息
@Select("select * from account")
@Results(id = "accountMap", value = {
@Result(id = true, property = "id", column = "id"),
@Result(property = "uid", column = "uid"),
@Result(property = "money", column = "money"),
//配置一对一的关系
@Result(property = "user", column = "uid", one = @One(select = "org.westos.dao.IUserDao.selectUserById", fetchType = FetchType.EAGER))
})
List<Account> findAll();
}
说明:
//配置一对一的关系 那么在@Result注解中有一个one属性可以配置一对一
/*
* property = "user" 多方维护的一方的对象
* column = "uid" 多方表中通过uid这个字段跟一方产生关系
* one 一对一关系的配置
select = "org.westos.dao.IUserDao.selectUserById" 查询依据 使用的是用户接口中通过id查询单个用户的这个方法
fetchType = FetchType.EAGER 加载模式,使用的立即加载
一般一对一的查询使用立即加载
一对多 使用延迟加载
* */
7.测试
public class TestAccount {
public static void main(String[] args) throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
IAccountDao dao = sqlSession.getMapper(IAccountDao.class);
List<Account> list = dao.findAll();
for (Account account : list) {
System.out.println(account);
//获取该账户对应得用户信息
User user = account.getUser();
System.out.println(user);
}
in.close();
sqlSession.close();
}
}
一对多的查询
我们站在用户的角度,那么一个用户肯定有多个账户
我们在用户的实体类中维护一个集合来描述这个一对多的关系
public class User implements Serializable {
private Integer myid;
private String myusername;
private Date mybirthday;
private String mysex;
private String myaddress;
//提供一个集合来描述一对多的关系
private List<Account> accounts;
//get set 方法略 自己 补上
}
1.我在User的接口中进行一对多的配置
public interface IUserDao {
//查询所有的方法
@Select(value = "select * from user")
@Results(id = "userMap", value = {
//配置主键字段 id = true 表示这是主键字段
@Result(id = true, property = "myid", column = "id"),
//配置其他普通字段
@Result(property = "myusername", column = "username"),
@Result(property = "mybirthday", column = "birthday"),
@Result(property = "mysex", column = "sex"),
@Result(property = "myaddress", column = "address"),
//配置一对多的关系
@Result(property = "accounts",column = "id",many = @Many(
select = "org.westos.dao.IAccountDao.findAccountById",
fetchType = FetchType.LAZY
))
})
List<User> findAll();
//根据id查询出一个用户
@Select(value = "select * from user where id=#{uid}")
@ResultMap(value = "userMap")
User selectUserById(Integer id);
}
说明:
//配置一对多的关系
// property = "accounts", 一方维护的集合名
// column = "id" 一方 id 这个字段跟多方产生关系
@Result(property = "accounts",column = "id",many = @Many(
//查询依据,使用账户接口中的方法根据uid查询该用户对应的账户
select = "org.westos.dao.IAccountDao.findAccountById",
fetchType = FetchType.LAZY //延迟加载
))
2.在账户的接口中提供一个方法,以便查询该用户对应的账户时,使用
public interface IAccountDao {
//查询所有账户,以及该账户所对应的用户信息
@Select("select * from account")
@Results(id = "accountMap", value = {
@Result(id = true, property = "id", column = "id"),
@Result(property = "uid", column = "uid"),
@Result(property = "money", column = "money"),
@Result(property = "user", column = "uid", one = @One(select = "org.westos.dao.IUserDao.selectUserById", fetchType = FetchType.EAGER))
})
List<Account> findAll();
//提供一个根据uid查询账户的方法
//注意是根据uid查询
@Select("select * from account where uid=#{uid}")
Account findAccountById(Integer id);
}
3.测试
@Test
public void test() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
IUserDao dao = sqlSession.getMapper(IUserDao.class);
List<User> list = dao.findAll();
for (User user : list) {
System.out.println(user);
//获取改用户所对应的账户信息
List<Account> accounts = user.getAccounts();
System.out.println(accounts);
}
in.close();
sqlSession.close();
}
一级缓存的演示
1、什么是缓存
存在于内存中的临时数据。
为什么使用缓存
减少和数据库的交互次数,提高执行效率。
什么样的数据能使用缓存,什么样的数据不能使用
适用于缓存:
经常查询并且不经常改变的。 省市区
数据的正确与否对最终结果影响不大的。小软文,自媒体写的花边新闻
不适用于缓存:
经常改变的数据
数据的正确与否对最终结果影响很大的。
例如:商品的库存,银行的汇率,股市的牌价。
Mybatis中的一级缓存
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。
public interface IUserDao2 {
//更新用户
@Update("update user set username=#{username},address=#{address} where id=#{id}")
void updateUser(User user);
//根据id查询出一个用户
@Select("select * from user where id=#{uid}")
User selectUserById(Integer id);
}
public class TestUserDao {
public static void main(String[] args) throws IOException {
//加载主配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//构建SessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
//获取sqlSession
SqlSession sqlSession = sessionFactory.openSession();
//获取接口的代理对象
IUserDao dao = sqlSession.getMapper(IUserDao.class);
//第一次查询,根据id查询出一个用户
User user = dao.selectUserById(59);
System.out.println(user); //不要重写toString方法,打印一下地址值
//sqlSession.clearCache();清空一级缓存
//第一次查询出用户后,我们更新用户,也会清空一级缓存
//user.setUsername("张全蛋");
//user.setAddress("陕西咸阳");
//dao.updateUser(user);
//再进行第二次查询,如果之前没有清空缓存,就会从缓存中查询,如果清空了,就从数据库中查询
User user2 = dao.selectUserById(59);
System.out.println(user2); //
System.out.println(user2==user); //对比两次查询的对象是否是同一个对象
sqlSession.commit();
//释放资源
in.close();
sqlSession.close();
}
}