本文共 23320 字,大约阅读时间需要 77 分钟。
目录
JNDI
NDI:Java Naming and Directory Interface。是SUN公司推出的一套规范,属于JavaEE技术之一。目的是模仿windows系统中的注册表。
在服务器中注册数据源:
1.创建Maven的war工程并导入坐标
org.mybatis mybatis 3.4.5 mysql mysql-connector-java 5.1.6 log4j log4j 1.2.12 junit junit 4.10 javax.servlet servlet-api 2.5 javax.servlet.jsp jsp-api 2.0
2.在webapp文件下创建META-INF目录
3.在META-INF目录中建立一个名为context.xml的配置文件
4.修改SqlMapConfig.xml中的配置
Mybatis中的延迟加载
在对应的四种表关系中:一对多,多对一,一对一,多对多 一对多,多对多:通常情况下我们都是采用延迟加载 多对一,一对一:通常情况下我们都是采用立即加载
使用 assocation 实现延迟加载
/****Title: IAccountDao
*Description: 账户的持久层接口
*Company: http://www.itheima.com/
*/public interface IAccountDao {/*** 查询所有账户,同时获取账户的所属用户名称以及它的地址信息* @return*/ListfindAll();}
select : 填写我们要调用的 select 映射的 idcolumn : 填写我们要传递给 select 映射的参数
/****Title: IUserDao
*Description: 用户的业务层接口
*Company: http://www.itheima.com/
*/public interface IUserDao {/*** 根据 id 查询* @param userId* @return*/User findById(Integer userId);}
/****Title: MybastisCRUDTest
*Description: 一对多账户的操作
*Company: http://www.itheima.com/
*/public class AccountTest {private InputStream in ;private SqlSessionFactory factory;private SqlSession session;private IAccountDao accountDao;@Testpublic void testFindAll() {//6.执行操作Listaccounts = accountDao.findAll();}@Before//在测试方法执行之前执行public void init()throws Exception {//1.读取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建构建者对象SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//3.创建 SqlSession 工厂对象factory = builder.build(in);//4.创建 SqlSession 对象session = factory.openSession();//5.创建 Dao 的代理对象accountDao = session.getMapper(IAccountDao.class);}@After//在测试方法执行完成之后执行public void destroy() throws Exception{//7.释放资源session.close();in.close();}}
使用 Collection 实现延迟加载
/****Title: User
*Description: 用户的实体类
*Company: http://www.itheima.com/
*/public class User implements Serializable {private Integer id;private String username;private Date birthday;private String sex;private String address;private Listaccounts;public List getAccounts() {return accounts;}public void setAccounts(List accounts) {this.accounts = accounts;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", birthday=" + birthday+ ", sex=" + sex + ", address="+ address + "]";}}
/*** 查询所有用户,同时获取出每个用户下的所有账户信息*/ListfindAll();/*** 根据用户 id 查询账户信息* @param uid* @return*/List findByUid(Integer uid);
<collection> 标签:主要用于加载关联的集合对象select 属性:用于指定查询 account 列表的 sql 语句,所以填写的是该 sql 映射的 idcolumn 属性:用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一 个字段名了
/****Title: MybastisCRUDTest
*Description: 一对多的操作
*Company: http://www.itheima.com/
*/public class UserTest {private InputStream in ;private SqlSessionFactory factory;private SqlSession session;private IUserDao userDao;@Testpublic void testFindAll() {//6.执行操作Listusers = userDao.findAll();}@Before//在测试方法执行之前执行public void init()throws Exception {//1.读取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建构建者对象SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//3.创建 SqlSession 工厂对象factory = builder.build(in);//4.创建 SqlSession 对象session = factory.openSession();//5.创建 Dao 的代理对象userDao = session.getMapper(IUserDao.class);}@After//在测试方法执行完成之后执行public void destroy() throws Exception{session.commit();//7.释放资源session.close();in.close();}}
Mybatis中的缓存
——存在于内存中的临时数据
使用缓存可以减少和数据库的交互次数,提高执行效率。 什么样的数据能使用缓存,什么样的数据不能使用 适用于缓存: 经常查询并且不经常改变的。 数据的正确与否对最终结果影响不大的 不适用于缓存: 经常改变的数据 数据的正确与否对最终结果影响很大的Mybatis中的一级缓存和二级缓存
一级缓存
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。 该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。当SqlSession对象消失时,mybatis的一级缓存也就消失了/****Title: IUserDao
*Description: 用户的业务层接口
*Company: http://www.itheima.com/
*/public interface IUserDao {/*** 根据 id 查询* @param userId* @return*/User findById(Integer userId);}
/****Title: MybastisCRUDTest
*Description: 一对多的操作
*Company: http://www.itheima.com/
*/public class UserTest {private InputStream in ;private SqlSessionFactory factory;private SqlSession session;private IUserDao userDao;@Testpublic void testFindById() {//6.执行操作User user = userDao.findById(41);System.out.println("第一次查询的用户:"+user);User user2 = userDao.findById(41);System.out.println("第二次查询用户:"+user2);System.out.println(user == user2);}@Before//在测试方法执行之前执行public void init()throws Exception {//1.读取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建构建者对象SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//3.创建 SqlSession 工厂对象factory = builder.build(in);//4.创建 SqlSession 对象session = factory.openSession();//5.创建 Dao 的代理对象userDao = session.getMapper(IUserDao.class);}@After//在测试方法执行完成之后执行public void destroy() throws Exception{//7.释放资源session.close();in.close();}}
测试结果如下:我们可以发现,虽然在上面的代码中我们查询了两次,但最后只执行了一次数据库操作,这就是 Mybatis 提供给我们的一级缓存在起作用了。因为一级缓存的存在,导致第二次查询 id 为 41 的记录时,并没有发出 sql 语句从数据库中查询数据,而是从一级缓存中查询
/*** 测试一级缓存*/@Testpublic void testFirstLevelCache(){User user1 = userDao.findById(41);System.out.println(user1);// sqlSession.close();//再次获取 SqlSession 对象// sqlSession = factory.openSession();sqlSession.clearCache();//此方法也可以清空缓存userDao = sqlSession.getMapper(IUserDao.class);User user2 = userDao.findById(41);System.out.println(user2);System.out.println(user1 == user2);}/*** 测试缓存的同步*/@Testpublic void testClearlCache(){//1.根据 id 查询用户User user1 = userDao.findById(41);System.out.println(user1);//2.更新用户信息user1.setUsername("update user clear cache");user1.setAddress("北京市海淀区");userDao.updateUser(user1);//3.再次查询 id 为 41 的用户User user2 = userDao.findById(41);System.out.println(user2);System.out.println(user1 == user2);}
当执行sqlSession.close()后,再次获取sqlSession并查询id=41的User对象时,又重新执行了sql 语句,从数据库进行了查询操作
二级缓存
它指的是Mybatis中SqlSessionFactory对象的缓存。二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
二级缓存的使用步骤: 第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置) 第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置) 第三步:让当前的操作支持二级缓存(在select标签中配置)/*** @author 黑马程序员* @Company http://www.ithiema.com*/public class SecondLevelCacheTest {private InputStream in;private SqlSessionFactory factory;@Before//用于在测试方法执行之前执行public void init()throws Exception{//1.读取配置文件,生成字节输入流in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.获取 SqlSessionFactoryfactory = new SqlSessionFactoryBuilder().build(in);}@After//用于在测试方法执行之后执行public void destroy()throws Exception{in.close();}/*** 测试一级缓存*/@Testpublic void testFirstLevelCache(){SqlSession sqlSession1 = factory.openSession();IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);User user1 = dao1.findById(41);System.out.println(user1);sqlSession1.close();//一级缓存消失SqlSession sqlSession2 = factory.openSession();IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);User user2 = dao2.findById(41);System.out.println(user2);sqlSession2.close();System.out.println(user1 == user2);}}
/****Title: User
*Description: 用户的实体类
*Company: http://www.itheima.com/
*/public class User implements Serializable {private Integer id;private String username;private Date birthday;private String sex;private String address;}
Mybatis中的注解开发
1 mybatis 的常用注解说明
2 使用 Mybatis 注解实现基本 CRUD
/****Title: User
*Description: 用户的实体类
*Company: http://www.itheima.com/
*/public class User implements Serializable {private Integer userId;private String userName;private Date userBirthday;private String userSex;private String userAddress;public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Date getUserBirthday() {return userBirthday;}public void setUserBirthday(Date userBirthday) {this.userBirthday = userBirthday;}public String getUserSex() {return userSex;}public void setUserSex(String userSex) {this.userSex = userSex;}public String getUserAddress() {return userAddress;}public void setUserAddress(String userAddress) {this.userAddress = userAddress;}@Overridepublic String toString() {return "User [userId=" + userId + ", userName=" + userName + ", userBirthday="+ userBirthday + ", userSex="+ userSex + ", userAddress=" + userAddress + "]";}}
/****Title: IUserDao
*Description: 用户的持久层接口
*Company: http://www.itheima.com/
*/public interface IUserDao {/*** 查询所有用户* @return*/@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")})ListfindAll();/*** 根据 id 查询一个用户* @param userId* @return*/@Select("select * from user where id = #{uid} ")@ResultMap("userMap")User findById(Integer userId);/*** 保存操作* @param user* @return*/@Insert("insert intouser(username,sex,birthday,address)values(#{username},#{sex},#{birthday},#{address})")@SelectKey(keyColumn="id",keyProperty="id",resultType=Integer.class,before =false, statement = { "select last_insert_id()" })int saveUser(User user);/*** 更新操作* @param user* @return*/@Update("update user setusername=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id} ")int updateUser(User user);/*** 删除用户* @param userId* @return*/@Delete("delete from user where id = #{uid} ")int deleteUser(Integer userId);/*** 查询使用聚合函数* @return*/@Select("select count(*) from user ")int findTotal();/*** 模糊查询* @param name* @return*/@Select("select * from user where username like #{username} ")List findByName(String name);}
通过注解方式,我们就不需要再去编写 UserDao.xml 映射文件了
3 编写 SqlMapConfig 配置文件
/****Title: MybatisAnnotationCRUDTest
*Description: mybatis 的注解 crud 测试
*Company: http://www.itheima.com/
*/public class MybatisAnnotationCRUDTest {/*** 测试查询所有*/@Testpublic void testFindAll() {Listusers = userDao.findAll();for(User user : users) {System.out.println(user);}}/*** 测试查询一个*/@Testpublic void testFindById() {User user = userDao.findById(41);System.out.println(user);}/*** 测试保存*/@Testpublic 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());}/*** 测试更新*/@Testpublic void testUpdate() {User user = userDao.findById(63);user.setUserBirthday(new Date());user.setUserSex("女");int res = userDao.updateUser(user);System.out.println(res);}/*** 测试删除*/@Testpublic void testDelete() {int res = userDao.deleteUser(63);System.out.println(res);}/*** 测试查询使用聚合函数*/@Testpublic void testFindTotal() {int res = userDao.findTotal();System.out.println(res);}/*** 测试模糊查询*/@Testpublic void testFindByName() {List users = userDao.findByName("%m%");for(User user : users) {System.out.println(user);}}private InputStream in;private SqlSessionFactory factory;private SqlSession session;private IUserDao userDao;@Before//junit 的注解public void init()throws Exception{//1.读取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建工厂SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();factory = builder.build(in);//3.创建 sessionsession = factory.openSession();//4.创建代理对象userDao = session.getMapper(IUserDao.class);}@After//junit 的注解public void destroy()throws Exception {//提交事务session.commit();//释放资源session.close();//关闭流in.close();}}
3 使用注解实现复杂关系映射开发
@Results 注解代替的是标签 <resultMap>该注解中可以使用单个 @Result 注解,也可以使用 @Result 集合@Results ( {@Result (), @Result () } )或 @Results ( @Result ())@Resutl 注解代替了 <id> 标签和 <result> 标签@Result 中 属性介绍:id 是否是主键字段column 数据库的列名property 需要装配的属性名one 需要使用的 @One 注解( @Result ( one=@One )()))many 需要使用的 @Many 注解( @Result ( many=@many )()))@One 注解(一对一)代替了 <assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。@One 注解属性介绍:select 指定用来多表查询的 sqlmapperfetchType 会覆盖全局的配置参数 lazyLoadingEnabled 。。使用格式:@Result (column= " " ,property= "" ,one= @One (select= "" ))@Many 注解(多对一)代替了 < Collection > 标签 , 是是多表查询的关键,在注解中用来指定子查询返回对象集合。注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList )但是注解中可以不定义;使用格式:@Result (property= "" ,column= "" ,many= @Many (select= "" ))
/****Title: User
*Description: 用户的实体类
*Company: http://www.itheima.com/
*/public class User implements Serializable {private Integer userId;private String userName;private Date userBirthday;private String userSex;private String userAddress;public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Date getUserBirthday() {return userBirthday;}public void setUserBirthday(Date userBirthday) {this.userBirthday = userBirthday;}public String getUserSex() {return userSex;}public void setUserSex(String userSex) {this.userSex = userSex;}public String getUserAddress() {return userAddress;}public void setUserAddress(String userAddress) {this.userAddress = userAddress;}@Overridepublic String toString() {return "User [userId=" + userId + ", userName=" + userName + ", userBirthday="+ userBirthday + ", userSex="+ userSex + ", userAddress=" + userAddress + "]";}}/****Title: Account
*Description: 账户的实体类
*Company: http://www.itheima.com/
*/public class Account implements Serializable {private Integer id;private Integer uid;private Double money;//多对一关系映射:从表方应该包含一个主表方的对象引用private User user;public User getUser() {return user;}public void setUser(User user) {this.user = user;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]";}}
/****Title: IAccountDao
*Description: 账户的持久层接口
*Company: http://www.itheima.com/
*/public interface IAccountDao {/*** 查询所有账户,采用延迟加载的方式查询账户的所属用户* @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"),@Result(column="uid",property="user",one=@One(select="com.itheima.dao.IUserDao.findById",fetchType=FetchType.LAZY))})ListfindAll();}
/****Title: IUserDao
*Description: 用户的持久层接口
*Company: http://www.itheima.com/
*/public interface IUserDao {/*** 查询所有用户* @return*/@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")})ListfindAll();/*** 根据 id 查询一个用户* @param userId* @return*/@Select("select * from user where id = #{uid} ")@ResultMap("userMap")User findById(Integer userId);}
/****Title: AccountTest
*Description: *
Company: http://www.itheima.com/
*/public class AccountTest {@Testpublic void testFindAll() {Listaccounts = accountDao.findAll();//for(Account account : accounts) {//System.out.println(account);//System.out.println(account.getUser());//}
/****Title: User
*Description: 用户的实体类
*Company: http://www.itheima.com/
*/public class User implements Serializable {private Integer userId;private String userName;private Date userBirthday;private String userSex;private String userAddress;//一对多关系映射:主表方法应该包含一个从表方的集合引用private Listaccounts;public List getAccounts() {return accounts;}public void setAccounts(List accounts) {this.accounts = accounts;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Date getUserBirthday() {return userBirthday;}public void setUserBirthday(Date userBirthday) {this.userBirthday = userBirthday;}public String getUserSex() {return userSex;}public void setUserSex(String userSex) {this.userSex = userSex;}public String getUserAddress() {return userAddress;}public void setUserAddress(String userAddress) {this.userAddress = userAddress;}@Overridepublic String toString() {return "User [userId=" + userId + ", userName=" + userName + ", userBirthday="+ userBirthday + ", userSex="+ userSex + ", userAddress=" + userAddress + "]";}}
/** **Title: IUserDao
*Description: 用户的持久层接口
*Company: http://www.itheima.com/
*/public interface IUserDao {/*** 查询所有用户* @return*/@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))})ListfindAll();}
@Many:
相当于<collection>的配置 select 属性:代表将要执行的 sql 语句 fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值
/****Title: IAccountDao
*Description: 账户的持久层接口
*Company: http://www.itheima.com/
*/public interface IAccountDao {/** * 根据用户 id 查询用户下的所有账户* @param userId* @return*/@Select("select * from account where uid = #{uid} ")ListfindByUid(Integer userId);}
/****Title: MybatisAnnotationCRUDTest
*Description: mybatis 的注解 crud 测试
*Company: http://www.itheima.com/
*/public class UserTest {/*** 测试查询所有*/@Testpublic void testFindAll() {Listusers = userDao.findAll();//for(User user : users) {//System.out.println("-----每个用户的内容-----");//System.out.println(user);//System.out.println(user.getAccounts());//}}private InputStream in;private SqlSessionFactory factory;private SqlSession session;private IUserDao userDao;@Before//junit 的注解public void init()throws Exception{//1.读取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建工厂SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();factory = builder.build(in);//3.创建 session session = factory.openSession();//4.创建代理对象userDao = session.getMapper(IUserDao.class);}@After//junit 的注解public void destroy()throws Exception {//提交事务session.commit();//释放资源session.close();//关闭流in.close();}}
通常来说,在一对多查多的时候用延迟加载,在一对一查一的时候通常用立即加载
mybatis 基于注解的二级缓存
/****Title: IUserDao
*Description: 用户的持久层接口
*Company: http://www.itheima.com/
*/@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存public interface IUserDao {}
转载地址:https://blog.csdn.net/m0_56426304/article/details/117921921 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!