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(); } }