mybatis是一个持久层框架,用java编写的。
它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程
它使用了ORM思想实现了结果集的封装。
ORM:
Object Relational Mappging 对象关系映射
简单的说:
就是把数据库表和实体类及实体类的属性对应起来
让我们可以操作实体类就实现操作数据库表。
user User
id userId
user_name userName
今天我们需要做到
实体类中的属性和数据库表的字段名称保持一致。
user User
id id
user_name user_name
mybatis的环境搭建
第一步:创建maven工程并导入坐标
第二步:创建实体类和dao的接口
第三步:创建Mybatis的主配置文件
SqlMapConifg.xml
第四步:创建映射配置文件
IUserDao.xml
环境搭建的注意事项:
第一个:创建IUserDao.xml 和 IUserDao.java时名称是为了和我们之前的知识保持一致。
在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper
所以:IUserDao 和 IUserMapper是一样的
第二个:在idea中创建目录的时候,它和包是不一样的
包在创建时:com.itheima.dao它是三级结构
目录在创建时:com.itheima.dao是一级目录
第三个:mybatis的映射配置文件位置必须和dao接口的包结构相同
第四个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
第五个:映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名
当我们遵从了第三,四,五点之后,我们在开发中就无须再写dao的实现类。
SqlMapConfig.xml
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/itheima/dao/IUserDao.xml"/>
mappers>
configuration>
IUserDao.xml
<mapper namespace="com.itheima.dao.IUserDao">
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
select>
mapper>
public static void main(String[] args) throws Exception{
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生成SqlSession对象
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
//6.释放资源
session.close();
in.close();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QxP6gDSe-1581003329506)(imgs/入门案例的分析.png)]
mybatis基于注解的入门案例:
把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句
同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。
明确:
我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式。
不管使用XML还是注解配置。
但是Mybatis它是支持写dao实现类的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5lRH8AT9-1581003329508)(imgs/自定义Mybatis分析.png)]
mybatis在使用代理dao的方式实现增删改查时做什么事呢?
只有两件事:
第一:创建代理对象
第二:在代理对象中调用selectList
自定义mybatis能通过入门案例看到类
class Resources
class SqlSessionFactoryBuilder
interface SqlSessionFactory
interface SqlSession
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DdQo0pQq-1581003329509)(imgs/自定义mybatis开发流程图.png)]
//查询所有用户
List<User> findAll();
//保存用户
void saveUser(User user);
<mapper namespace="com.tang.dao.IUserDao">
<select id="findAll" resultType="com.tang.domain.User">
select * from user;
select>
<insert id="saveUser" parameterType="com.tang.domain.User">
insert into user(username,address,sex,birthday)
values (#{username},#{address},#{sex},#{birthday});
insert>
mapper>
package com.tang.test;
import com.tang.dao.IUserDao;
import com.tang.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisTest {
private InputStream in;
private SqlSession sqlSession;
private IUserDao userDao;
@Before
public void init() throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
sqlSession = factory.openSession();
userDao = sqlSession.getMapper(IUserDao.class);
}
@After
public void destory() throws Exception{
sqlSession.commit();
sqlSession.close();
in.close();
}
/**
* 测试查询所有
*/
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testSave(){
User user = new User();
user.setUsername("tangjiadong");
user.setAddress("苏州市高新区");
user.setSex("男");
user.setBirthday(new Date());
userDao.saveUser(user);
}
}
//更新用户
void updateUser(User user);
//删除用户
void deleteUser(Integer userId);
<update id="updateUser" parameterType="USER">
update user set username=#{userName},address=#{userAddress},sex=#{userAex},birthday=#{userBirthday} where id=#{userId}
update>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{uid}
delete>
/**
* 测试更新操作
*/
@Test
public void testUpdate(){
User user = new User();
user.setUserId(50);
user.setUserName("mybastis update user");
user.setUserAddress("北京市顺义区");
user.setUserSex("女");
user.setUserBirthday(new Date());
//5.执行保存方法
userDao.updateUser(user);
}
/**
* 测试删除操作
*/
@Test
public void testDelete(){
//5.执行删除方法
userDao.deleteUser(48);
}
//根据id查询用户信息
User findById(Integer userId);
//根据名称模糊查询用户信息
List<User> findByName(String username);
<select id="findById" parameterType="INT" resultMap="userMap">
select * from user where id = #{uid}
select>
<select id="findByName" parameterType="string" resultMap="userMap">
select * from user where username like #{name}
select>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uOHNLhuo-1581003329511)(imgs/无标题.png)]
/**
* 测试查询一个操作
*/
@Test
public void testFindOne(){
//5.执行查询一个方法
User user = userDao.findById(50);
System.out.println(user);
}
/**
* 测试模糊查询操作
*/
@Test
public void testFindByName(){
//5.执行查询一个方法
List<User> users = userDao.findByName("%王%");
// List users = userDao.findByName("王");
for(User user : users){
System.out.println(user);
}
}
//查询总用户数
int findTotal();
<select id="findTotal" resultType="int">
select COUNT(id) from user;
select>
@Test
public void testFindCount(){
int total = userDao.findTotal();
System.out.println(total);
}
<insert id="saveUser" parameterType="com.tang.domain.User">
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
selectKey>
insert into user(username,address,sex,birthday)
values (#{username},#{address},#{sex},#{birthday});
insert>
由多个条件组成一个对象来查询
OGNL表达式:
Object Graphic Navigation Language
对象 图 导航 语言
它是通过对象的取值方法来获取数据。在写法上把get给省略了。
比如:我们获取用户的名称
类中的写法:user.getUsername();
OGNL表达式写法:user.username
mybatis中为什么能直接写username,而不用user.呢:
因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名
//根据queryVo中的条件查询用户
List<User> findUserByVo(QueryVo vo);
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
<select id="findUserByVo" parameterType="com.tang.domain.QueryVo" resultType="com.tang.domain.User">
SELECT * from user where username like #{user.username}
select>
/**
* 测试使用QueryVo作为查询条件
*/
@Test
public void testFindByVo(){
QueryVo vo = new QueryVo();
User user = new User();
user.setUserName("%王%");
vo.setUser(user);
//5.执行查询一个方法
List<User> users = userDao.findUserByVo(vo);
for(User u : users){
System.out.println(u);
}
}
解决实体类属性和数据库列明不对应的两种方式
select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;
<resultMap id="userMap" type="uSeR">
<id property="userId" column="id">id>
<result property="userName" column="username">result>
<result property="userAddress" column="address">result>
<result property="userSex" column="sex">result>
<result property="userBirthday" column="birthday">result>
resultMap>
SqlMapConfig.xml
<configuration>
<properties url="file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">
properties>
<typeAliases>
<package name="com.itheima.domain">package>
typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}">property>
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
dataSource>
environment>
environments>
<mappers>
<package name="com.itheima.dao">package>
mappers>
configuration>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MidVolT5-1581003329513)(imgs/无标题-1578128644905.png)]
1、连接池:
我们在实际开发中都会使用连接池。
因为它可以减少我们获取连接所消耗的时间。
2、mybatis中的连接池
mybatis连接池提供了3种方式的配置:
配置的位置:
主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。
type属性的取值:
POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。
注意:如果不是web或者maven的war工程,是不能使用的。
我们课程中使用的是tomcat服务器,采用连接池就是dbcp连接池。
mybatis中的事务
什么是事务
事务的四大特性ACID
不考虑隔离性会产生的3个问题
解决办法:四种隔离级别
它是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚
解决:传入值不确定是什么类型
/**
* 根据传入参数条件
* @param user 查询的条件:有可能有用户名,有可能有性别,也有可能有地址,还有可能是都有
* @return
*/
List<User> findUserByCondition(User user);
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user where 1=1
<if test="userName != null">
and username = #{userName}
if>
select>
/**
* 测试查询所有
*/
@Test
public void testFindByCondition(){
User u = new User();
u.setUserName("老王");
// u.setUserSex("女");
//5.执行查询所有方法
List<User> users = userDao.findUserByCondition(u);
for(User user : users){
System.out.println(user);
}
}
解决 where1=1的问题
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user
<where>
<if test="userName != null">
and username = #{userName}
if>
<if test="userSex != null">
and sex = #{userSex}
if>
where>
select>
select * from user where id in(41,42,43);
加ids属性
public class QueryVo {
private User user;
private List<Integer> ids;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
/**
* 根据queryvo中提供的id集合,查询用户信息
* @param vo
* @return
*/
List<User> findUserInIds(QueryVo vo);
<sql id="defaultUser">
select * from user
sql>
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
<include refid="defaultUser">include>
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
foreach>
if>
where>
select>
/**
* 测试foreach标签的使用
*/
@Test
public void testFindInIds(){
QueryVo vo = new QueryVo();
List<Integer> list = new ArrayList<Integer>();
list.add(41);
list.add(42);
list.add(46);
vo.setIds(list);
//5.执行查询所有方法
List<User> users = userDao.findUserInIds(vo);
for(User user : users){
System.out.println(user);
}
}
mybatis中的多表查询:
示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1、建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2、建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出来一对多的关系
3、建立两个配置文件
用户的配置文件
账户的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息
示例:用户和角色
一个用户可以有多个角色
一个角色可以赋予多个用户
步骤:
1、建立两张表:用户表,角色表
让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
2、建立两个实体类:用户实体类和角色实体类
让用户和角色的实体类能体现出来多对多的关系
各自包含对方一个集合引用
3、建立两个配置文件
用户的配置文件
角色的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户所包含的角色信息
当我们查询角色时,可以同时得到角色的所赋予的用户信息
public class AccountUser extends Account{
private String username;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return super.toString() +"AccountUser{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
}
/**
* 查询所有账户,并且带有用户名称和地址信息
* @return
*/
List<AccountUser> findAllAccount();
<select id="findAll" resultMap="accountUserMap">
select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
select>
/**
* 测试查询所有账户,同时包含用户名称和地址
*/
@Test
public void testFindAllAccountUser(){
List<AccountUser> aus = accountDao.findAllAccount();
for(AccountUser au : aus){
System.out.println(au);
}
}
public class Account implements Serializable{
private Integer id;
private Integer uid;
private Double money;
//从表实体应该包含一个主表实体的对象引用
private User user;
....
}
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid">id>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<association property="user" column="uid" javaType="user">
<id property="id" column="id"/>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
association>
resultMap>
<select id="findAll" resultMap="accountUserMap">
SELECT u.*,a.id as aid,a.uid,a.money from account a ,user u where u.id=a.uid;
select>
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for (Account au : accounts) {
System.out.println("---------每个account的信息------------");
System.out.println(au);
System.out.println(au.getUser());
}
}
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多关系映射,主表实体应该包含从表实体的集合引用
private List<Account> accounts;
//getter,setter方法
...
}
<resultMap id="userAccountMap" type="user">
<id property="id" column="id">id>
<result property="username" column="username">result>
<result property="address" column="address">result>
<result property="sex" column="sex">result>
<result property="birthday" column="birthday">result>
<collection property="accounts" ofType="account">
<id column="aid" property="id">id>
<result column="uid" property="uid">result>
<result column="money" property="money">result>
collection>
resultMap>
<select id="findAll" resultMap="userAccountMap">
select * from user u left outer join account a on u.id = a.uid
select>
/**
* 测试查询所有
*/
@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());
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-arV7JQpD-1581003329515)(imgs/1578152907045.png)]
public class Role {
private Integer roleId;
private String roleName;
private String roleDesc;
//多对多关系映射:一个角色可以赋予多个用户
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
...
}
<mapper namespace="com.itheima.dao.IRoleDao">
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid">id>
<result property="roleName" column="role_name">result>
<result property="roleDesc" column="role_desc">result>
<collection property="users" ofType="user">
<id column="id" property="id">id>
<result column="username" property="username">result>
<result column="address" property="address">result>
<result column="sex" property="sex">result>
<result column="birthday" property="birthday">result>
collection>
resultMap>
<select id="findAll" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r
left outer join user_role ur on r.id = ur.rid
left outer join user u on u.id = ur.uid
select>
mapper>
@Test
public void testFindAll(){
List<Role> roles = roleDao.findAll();
for(Role role : roles){
System.out.println("---每个角色的信息----");
System.out.println(role);
System.out.println(role.getUsers());
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zbu8UEpF-1581003329516)(imgs/延迟加载.png)]
问题:在一对多中,当我们有一个用户,它有100个账户。
在查询用户的时候,要不要把关联的账户查出来?
在查询账户的时候,要不要把关联的用户查出来?
在查询用户时,用户下的账户信息应该是,什么时候使用,什么时候查询的。
在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。
什么是延迟加载
在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
什么是立即加载
不管用不用,只要一调用方法,马上发起查询。
在对应的四种表关系中:一对多,多对一,一对一,多对多
一对多,多对多:通常情况下我们都是采用延迟加载。
多对一,一对一:通常情况下我们都是采用立即加载。
SqlMapConfig.xml中配置参数
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
<mapper namespace="com.itheima.dao.IAccountDao">
<resultMap id="accountUserMap" type="account">
<id property="id" column="id">id>
<result property="uid" column="uid">result>
<result property="money" column="money">result>
<association property="user" column="uid" javaType="user" select="com.itheima.dao.IUserDao.findById">association>
resultMap>
<select id="findAll" resultMap="accountUserMap">
select * from account
select>
mapper>
/**
* 根据用户id查询账户信息
* @param uid
* @return
*/
List<Account> findAccountByUid(Integer uid);
IAccountDao.xml
<select id="findAccountByUid" resultType="account">
SELECT * from account where uid = #{uid}
select>
IUserDao.xml
<resultMap id="userAccountMap" type="user">
<id property="id" column="id">id>
<result property="username" column="username">result>
<result property="address" column="address">result>
<result property="sex" column="sex">result>
<result property="birthday" column="birthday">result>
<collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id">collection>
resultMap>
<select id="findAll" resultMap="userAccountMap">
select * from user
select>
什么是缓存
存在于内存中的临时数据。
为什么使用缓存
减少和数据库的交互次数,提高执行效率。
什么样的数据能使用缓存,什么样的数据不能使用
适用于缓存:
经常查询并且不经常改变的。
数据的正确与否对最终结果影响不大的。
不适用于缓存:
经常改变的数据
数据的正确与否对最终结果影响很大的。
例如:商品的库存,银行的汇率,股市的牌价。
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
sqlSession.clearCache();
触发清空一级缓存情况
/**
* 更新用户信息
* @param user
*/
void updateUser(User user);
<update id="updateUser" parameterType="user">
update user set username=#{username},address=#{address} where id=#{id}
update>
/**
* 测试缓存的同步
*/
@Test
public 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的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
第三步:让当前的操作支持二级缓存(在select标签中配置)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YccAVlYT-1581003329517)(imgs/二级缓存.png)]
SqlMapConfig.xml
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
<mapper namespace="com.itheima.dao.IUserDao">
<cache/>
<select id="findAll" resultType="user">
select * from user
select>
<select id="findById" parameterType="INT" resultType="user" useCache="true">
select * from user where id = #{uid}
select>
<update id="updateUser" parameterType="user">
update user set username=#{username},address=#{address} where id=#{id}
update>
mapper>
public class SecondLevelCacheTest {
private InputStream in;
private SqlSessionFactory factory;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
factory = new SqlSessionFactoryBuilder().build(in);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
in.close();
}
/**
* 测试一级缓存
*/
@Test
public 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);
}
}
SqlMapConfig.xml
(mapper注意使用class)
<configuration>
<properties resource="jdbcConfig.properties">properties>
<typeAliases>
<package name="com.itheima.domain">package>
typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}">property>
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
dataSource>
environment>
environments>
<mappers>
<mapper class="com.itheima.dao.IUserDao">mapper>
mappers>
configuration>
public interface IUserDao {
//查询所有用户
@Select("select * from user")
List<User> findAll();
}
public static void main(String[] args) throws Exception{
//1.获取字节输入流
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.根据字节输入流构建SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.根据SqlSessionFactory生产一个SqlSession
SqlSession session = factory.openSession();
//4.使用SqlSession获取Dao的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.执行Dao方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
//6.释放资源
session.close();
in.close();
}
//保存用户
@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} ")
@Select("select * from user where username like '%${value}%'")
List<User> findUserByName(String username);
//查询用户总数
@Select("select count(*) from user")
int findTotalUser();
@Test
public void testUpdate(){
User user = new User();
user.setId(51);
user.setUsername("mybatis annotation update");
user.setAddress("北京市海淀区");
user.setSex("男");
user.setBirthday(new Date());
userDao.updateUser(user);
}
@Test
public void testDelete(){
userDao.deleteUser(51);
}
@Test
public void testFindOne(){
User user = userDao.findById(50);
System.out.println(user);
}
@Test
public void testFindByName(){
// List users = userDao.findUserByName("%mybatis%");
List<User> users = userDao.findUserByName("王");
for(User user : users){
System.out.println(user);
}
}
@Test
public void testFindTotal(){
int total = userDao.findTotalUser();
System.out.println(total);
}
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 = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday")
})
List<User> findAll();
/**
* 根据id查询用户
* @param userId
* @return
*/
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
/**
* 根据用户名称模糊查询
* @param username
* @return
*/
@Select("select * from user where username like #{username} ")
@ResultMap("userMap")
List<User> findUserByName(String username);
}
@one标签里的column代表用哪个字段去查
//多对一(mybatis中称之为一对一)的映射:一个账户只能属于一个用户
private User user;
<mappers>
<package name="com.itheima.dao">package>
mappers>
public interface IAccountDao {
//查询所有账户,并且获取每个账户所属的用户信息
@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.EAGER))
})
List<Account> findAll();
}
//一对多关系映射:一个用户对应多个账户
private List<Account> accounts;
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();
IAccountDao
//根据用户id查询账户信息
@Select("select * from account where uid = #{userId}")
List<Account> findAccountByUid(Integer userId);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XkkJ9eSZ-1581003329519)(imgs/1578213803080.png)]
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
@CacheNamespace(blocking = true)
public interface IUserDao {
....
}
package com.itheima.test;
import com.itheima.dao.IUserDao;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
/**
* @author 黑马程序员
* @Company http://www.ithiema.com
*/
public class SecondLevelCatchTest {
private InputStream in;
private SqlSessionFactory factory;
@Before
public void init()throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
}
@After
public void destroy()throws Exception{
in.close();
}
@Test
public void testFindOne(){
SqlSession session = factory.openSession();
IUserDao userDao = session.getMapper(IUserDao.class);
User user = userDao.findById(50);
System.out.println(user);
session.close();//释放一级缓存
SqlSession session1 = factory.openSession();//再次打开session
IUserDao userDao1 = session1.getMapper(IUserDao.class);
User user1 = userDao1.findById(50);
System.out.println(user1);
session1.close();
}
}