MyBatis小记_three

目录

注解开发

环境搭建

1.创建Maven工程

2.创建实体类

3.提供接口,并提供增删改查的方法

4.编写SqlMapConfig.xml 主配置文件

5.采用注解的方式,来进行增删改查

6.测试

7.测试保存用户的方法

8.测试更新用户

9.测试删除一个用户

10.根据id查询一个用户

11.根据姓名模糊查询

12.查询所有用户的个数

当实体类的属性名和表中的字段名不一致时,采用注解怎么配置

1.修改实体类的属性名

2.配置实体类的属性和表中字段的映射关系

使用注解进行多表查询

一对一的关系查询:比如查询该账户所对应的用户信息

1.提供账户的实体类

2.提供账户的接口

3.给账户接口上的方法,添加注解,先查询出所有账户

4.测试

5.上面还只是一个单表查询的测试,下来我们要进行多表查询,查询一个账户所对应的用户信息

6.在账户的接口中添加注解,来进行一对一的查询

7.测试

一对多的查询

1.我在User的接口中进行一对多的配置

2.在账户的接口中提供一个方法,以便查询该用户对应的账户时,使用

3.测试

一级缓存的演示


注解开发

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