MyBatis-04

MyBatis-04

一、Mybatis的延迟加载

在多表关联查询时,比如查询用户信息,及其关联的帐号信息,在查询用户时就直接把帐号信息也一并查询出来了。但是在实际开发中,并不是每次都需要立即使用帐号信息,这时候,就可以使用延迟加载策略了。

1. 什么是延迟加载

1.1 立即加载的概念

不管数据是否需要使用,只要调用了方法,就立即发起查询。比如:上节课的多表关联查询,查询帐号,得到关联的用户。

1.2 延迟加载的概念

延迟加载,也叫按需加载,或者叫懒加载。只有当真正使用到数据的时候,才发起查询。不使用不发起查询。比如:查询用户信息,不使用accounts的时候,不查询帐号的数据;只有当使用了用户的accounts,Mybatis再发起查询帐号的信息

  • 好处:先从单表查询,需要使用关联数据时,才进行关联数据的查询。 单表查询的速度要比多表关联查询速度快
  • 坏处:当需要使用数据时才会执行SQL。这样大批量的SQL执行的情况下,会造成查询等待时间比较长
1.3 延迟加载的使用场景
  • 一对一(多对一),通常不使用延迟加载(建议)。比如:查询帐号,关联加载用户信息
  • 一对多(多对多),通常使用延迟加载(建议)。比如:查询用户,关联加载帐号信息
1.4 ★★★★懒加载实现的过程★★★★

​ 只有多表关联查询时,才需要懒加载。

  1. 一对一的懒加载
    • 修改JavaBean-Account,需要有另外一个JavaBean(User)的引用
    • 准备好关联查询使用的方法:根据id查询User对象----findUserByUid
    • 在映射器接口里编写查询的代码:查询帐号信息的功能
    • 在映射配置文件里,封装结果使用resultMap和association标签。
      • association:需要增加两个属性
        • select:调用已经准备好的方法,懒加载关联查询
        • column:调用准备好的方法时,需要的参数从哪个字段里取
    • 修改Mybatis的核心配置文件,开启延迟加载
  2. 一对多的懒加载
    • 修改JavaBean-User,需要有另外一个JavaBean(Account)的集合
    • 准备好关联查询使用的方法:根据uid查询得到Account的集合—findAccountsByUid
    • 在映射器接口里编写查询用户的代码:
    • 在映射配置文件里,封装结果使用resultMap和collection标签。
      • collection:需要增加两个属性
        • select:调用已经准备好的方法,懒加载关联查询。com.viking.dao.IAccountDao.findAccountsByUid
        • column:调用准备好的方法时,需要的参数从哪个字段里取
    • 修改Mybatis的核心配置文件,开启延迟加载

2. 实现一对一(多对一)的延迟加载

需求:查询帐号信息,及其关联的用户信息。使用懒加载的方式实现。

2.1 一对一延迟加载的要点
  • 要有映射器IUserDao,提供findUserById的方法,供懒加载时使用
  • 要有映射器IAccountDao查询帐号信息,使用association实现懒加载关联的用户信息
  • 在核心配置文件中,开启懒加载
2.2 准备关联加载的方法备用(IUserDao.findUserById)
  1. 创建Maven的Java项目,设置坐标,配置好Mybatis的依赖

  2. 创建JavaBean:User和Account

    注意:Account中要有User的引用

    public class User {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        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;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    }
    
    public class Account {
        private Integer id;
        private Integer uid;
        private Double money;
    
        private 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;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", uid=" + uid +
                    ", money=" + money +
                    ", user=" + user +
                    '}';
        }
    }
    
  3. 创建映射器接口IUserDao,提供findUserById方法(准备好备用)

    public interface IUserDao {
        User findUserById(Integer uid);
    }
    
  4. 创建映射配置文件IUserDao.xml(准备好备用)

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.viking.dao.IUserDao">
        <select id="findUserById" parameterType="int" resultType="user">
            select * from user where id = #{uid}
        </select>
    </mapper>
    
  5. 创建Mybatis的核心配置文件,配置好别名和映射器

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <package name="com.viking.bean"/>
        </typeAliases>
    
        <environments default="mysql_mybatis">
            <environment id="mysql_mybatis">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <package name="com.viking.dao"/>
        </mappers>
    </configuration>
    
2.3 查询帐号信息,调用准备好的关联加载的方法,实现懒加载
  1. 创建映射器接口IAccountDao

    public interface IAccountDao {
        /**
         * 查询一个帐号信息,懒加载关联的用户信息
         */
        Account findById(Integer id);
    }
    
  2. 创建映射配置文件IAccountDao.xml,配置映射信息

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.viking.dao.IAccountDao">
        
        <select id="findById" parameterType="int" resultMap="accountLazyUser">
            select * from account where id = #{id}
        </select>
        
        <resultMap id="accountLazyUser" type="account">
            <id property="id" column="id"/>
            <result property="uid" column="uid"/>
            <result property="money" column="money"/>
    
            <!--
            association标签:用于封装关联的JavaBean对象
                select:调用哪个statement,懒加载 得到关联的JavaBean对象
                column:调用statement时,需要传递的参数值,从哪个字段中取出
            -->
            <association property="user" javaType="user"
                         column="uid" select="com.viking.dao.IUserDao.findUserById"/>
        </resultMap>
    </mapper>
    
  3. 修改Mybatis的核心配置文件,启动延迟加载

    <!-- 把settings标签放到typeAliases之前 -->
    <settings>
        <!-- 启动延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 禁用积极加载:使用按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    
  4. 编写测试代码

    public class MybatisLazyTest {
        private InputStream is;
        private SqlSession session;
        private IAccountDao accountDao;
    
        /**
         * 测试  一对一的延迟加载效果
         */
        @Test
        public void testFindAccountById(){
            Account account = accountDao.findById(1);
            System.out.println(account.getId()+",  " +account.getMoney());
            
            //如果不执行下面这行代码,Mybatis是不会发起查询用户信息的SQL语句的。
            System.out.println(account.getUser());
        }
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(is);
            session = factory.openSession();
            accountDao = session.getMapper(IAccountDao.class);
        }
    
        @After
        public void destory() throws IOException {
            session.close();
            is.close();
        }
    }
    

3. 实现一对多(多对多)的延迟加载

需求:查询用户信息,及其关联的帐号信息集合。使用延迟加载实现。

3.1 一对多延迟加载的要点
  • 要有映射器IAccountDao,提供findAccountsByUid的方法,供懒加载时使用
  • 要有映射器IUserDao,查询用户信息,使用collection实现懒加载帐号关联的帐号信息
  • 在核心配置文件中,开启懒加载
3.2 准备关联加载的方法备用(IAccountDao.findAccountsByUid)
  1. 创建Maven的Java项目,配置好坐标,引入Mybatis的依赖

  2. 创建JavaBean:User和Account

    注意:User中要有Account的集合

    public class Account {
        private Integer id;
        private Integer uid;
        private Double money;
    
        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;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", uid=" + uid +
                    ", money=" + money +
                    '}';
        }
    }
    
    public class User {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        private List<Account> 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;
        }
    
        public List<Account> getAccounts() {
            return accounts;
        }
    
        public void setAccounts(List<Account> accounts) {
            this.accounts = accounts;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    ", accounts=" + accounts +
                    '}';
        }
    }
    
  3. 创建映射器接口IAccountDao,提供findAccountsByUid方法(准备好备用)

    public interface IAccountDao {
        List<Account> findAccountsByUid(Integer uid);
    }
    
  4. 创建映射配置文件IAccountDao.xml,配置映射信息

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.viking.dao.IAccountDao">
        <select id="findAccountsByUid" resultType="account">
            select * from account where uid = #{uid}
        </select>
    </mapper>
    
  5. 准备Mybatis的核心配置文件,配置好别名和映射器

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <package name="com.viking.bean"/>
        </typeAliases>
    
        <environments default="mysql_mybatis">
            <environment id="mysql_mybatis">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <package name="com.viking.dao"/>
        </mappers>
    </configuration>
    
3.3 查询用户信息,调用准备好的关联加载的方法,实现懒加载
  1. 创建映射器接口IUserDao

    public interface IUserDao {
        /**
         * 查询一个用户信息,懒加载关联的帐号信息集合
         * @return
         */
        User findUserById(Integer uid);
    }
    
  2. 创建映射配置文件IUserDao.xml

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.viking.dao.IUserDao">
        
        <select id="findUserById" parameterType="int" resultMap="userLazyAccounts">
            select * from user where id = #{uid}
        </select>
        
        <resultMap id="userLazyAccounts" type="user">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
    
            <collection property="accounts" ofType="account" column="id" 		
                        select="com.viking.dao.IAccountDao.findAccountsByUid"/>
        </resultMap>
    </mapper>
    
  3. 修改Mybatis核心配置文件,开启延迟加载

    <!-- 把settings标签放到typeAliases之前 -->
    <settings>
        <!-- 启动延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 禁用积极加载:使用按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    
  4. 编写测试代码

    public class MybatisLazyTest {
        private InputStream is;
        private SqlSession session;
        private IUserDao userDao;
    
        /**
         * 测试  一对多的延迟加载效果
         */
        @Test
        public void testFindUserById(){
            User user = userDao.findUserById(41);
            System.out.println(user.getUsername() + ",  " + user.getAddress());
            
            //如果不执行下面这行代码,Mybatis是不会发起查询帐号信息的SQL语句的
            System.out.println(user.getAccounts());
        }
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(is);
            session = factory.openSession();
            userDao = session.getMapper(IUserDao.class);
        }
    
        @After
        public void destory() throws IOException {
            session.close();
            is.close();
        }
    }
    

二、Mybatis的缓存

Mybatis为了提高数据查询的效率,也提供了缓存的功能:一级缓存和二级缓存。

  • 一级缓存:是SqlSession对象提供的缓存
  • 二级缓存:是SqlSessionFactory对象的缓存,同一个SqlSessionFactory创建的多个SqlSession共享缓存

我们以查询一个用户信息为例,来演示Mybatis缓存的效果。

1. 准备Mybatis环境

  1. 创建Maven的Java项目,配置好坐标,引入Mybatis的依赖

  2. 创建JavaBean:User

    注意:不要重写toString()方法,我们需要打印User对象的地址

    public class User {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        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;
        }
    }
    
  3. 创建映射器接口IUserDao

    public interface IUserDao {
        User findUserById(Integer uid);
    }
    
  4. 创建映射配置文件IUserDao.xml

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.viking.dao.IUserDao">
        <select id="findUserById" parameterType="int" resultType="user">
            select * from user where id = #{uid}
        </select>
    </mapper>
    
  5. 准备Mybatis的核心配置文件,配置好别名和映射器

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <package name="com.viking.bean"/>
        </typeAliases>
    
        <environments default="mysql_mybatis">
            <environment id="mysql_mybatis">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <package name="com.viking.dao"/>
        </mappers>
    </configuration>
    
  6. 准备好单元测试类备用

    /**
     * Mybatis一级缓存效果演示
     */
    public class MybatisLevel1CacheTest {
        private InputStream is;
        private SqlSession session;
        private IUserDao dao;
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(is);
            session = factory.openSession();
            dao = session.getMapper(IUserDao.class);
        }
    
        @After
        public void destory() throws IOException {
            session.close();
            is.close();
        }
    }
    

2. 一级缓存

2.1 什么是一级缓存

一级缓存,是SqlSession对象提供的缓存(无论用不用,始终都有的)。

当我们执行一次查询之后,查询的结果会同时缓存到SqlSession提供的一块存储区域中(是一个Map)。当我们再次查询同样的数据,Mybatis会优先从缓存中查找;如果找到了,就不再查询数据库。

2.2 一级缓存的清除

当调用了SqlSession对象的修改、添加、删除、commit()、close()、clearCache()等方法时,一级缓存会被清空。

2.3 一级缓存效果演示
    /**
     * 测试 Mybatis的一级缓存:
     * SQL语句执行了一次、输出user1和user2的地址是相同的
     * 说明Mybatis使用了缓存
     */
    @Test
    public void testLevel1Cache(){
        User user1 = dao.findUserById(41);
        System.out.println(user1);

        User user2 = dao.findUserById(41);
        System.out.println(user2);
    }

    /**
     * 测试  清除Mybatis的一级缓存
     * 两次打印的User地址不同,执行了两次SQL语句
     * SqlSession的修改、添加、删除、commit()、clearCache()、close()都会清除一级缓存
     */
    @Test
    public void testClearLevel1Cache(){
        User user1 = dao.findUserById(41);
        System.out.println(user1);

        session.clearCache();

        User user2 = dao.findUserById(41);
        System.out.println(user2);
    }

3. 二级缓存

3.1 什么是二级缓存

​ 指Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象生产的SqlSession对象共享其缓存。二级缓存需要手动开启

3.2 开启二级缓存,及效果演示
  1. 修改Mybatis核心配置文件,开启全局的二级缓存开关

    <!-- 把设置项添加到核心配置文件内,typeAliases之前 -->
    <settings>
        <!-- 增加此配置项,启动二级缓存(默认值就是true,所以这一步可以省略不配置) -->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. 修改映射配置文件IUserDao.xml,让映射器支持二级缓存

    <mapper namespace="com.viking.dao.IUserDao">
        <!-- 把cache标签加到映射配置文件 mapper标签里 -->
        <cache/>
        ......
    </mapper>
    
  3. 修改映射配置文件IUserDao中的findById,让此方法(statement)支持二级缓存

    <!-- 如果statement的标签上,设置有的useCache="true",表示此方法要使用二级缓存 -->
    <select id="findById" parameterType="int" resultType="user" useCache="true">
        select * from user where id = #{id}
    </select>
    
  4. 修改JavaBean:User

    注意:如果要使用二级缓存,那么JavaBean需要实现Serializable接口

    public class User implements Serializable {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        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;
        }
    }
    
  5. 编写测试代码

    /**
     * Mybatis二级缓存效果演示
     */
    public class MybatisLevel2CacheTest {
        private InputStream is;
        private SqlSessionFactory factory;
    
        /**
         * 测试二级缓存。
         * 测试结果:
         *      虽然输出的user1和user2地址不同,但是SQL语句只执行了一次。
         *      Mybatis的二级缓存,保存的不是JavaBean对象,而是散列的数据。
         *      当要获取缓存时,把这些数据重新组装成一个JavaBean对象,所以地址不同
         */
        @Test
        public void testLevel2Cache(){
            SqlSession session1 = factory.openSession();
            IUserDao dao1 = session1.getMapper(IUserDao.class);
            User user1 = dao1.findUserById(41);
            System.out.println(user1);
            session1.close();
    
            SqlSession session2 = factory.openSession();
            IUserDao dao2 = session2.getMapper(IUserDao.class);
            User user2 = dao2.findUserById(41);
            System.out.println(user2);
            session2.close();
        }
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            factory = builder.build(is);
        }
    
        @After
        public void destory() throws IOException {
            is.close();
        }
    }
    

三、Mybatis的注解开发

Mybatis也支持注解开发。但是需要明确的是,Mybatis仅仅是把映射配置文件 使用注解代替了;而Mybatis的核心配置文件,仍然是xml配置。

1. 常用注解介绍

  • @Select:相当于映射配置文件里的select标签
  • @Insert:相当于映射配置文件里的insert标签
  • @SelectKey:相当于映射配置文件里的selectKey标签,用于添加数据后获取最新的主键值
  • @Update:相当于映射配置文件里的update标签
  • @Delete:相当于映射配置文件里的delete标签
  • @Results:相当于映射配置文件里的resultMap标签
  • @Result:相当于映射配置文件里的result标签,和@Results配合使用,封装结果集的
  • @One:相当于映射配置文件里的association,用于封装关联的一个JavaBean对象
  • @Many:相当于映射配置文件里的collection标签,用于封装关联的一个JavaBean对象集合

2. 使用注解实现简单CURD操作

2.1 准备Mybatis环境
  1. 创建Maven的Java项目,配置好坐标,并引入Mybatis的依赖

  2. 创建JavaBean:User

    public class User {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        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;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    }
    
  3. 创建映射器接口IUserDao,备用

    public interface IUserDao {
    
    }
    
  4. 准备Mybatis的核心配置文件,配置好别名和映射器

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <package name="com.viking.bean"/>
        </typeAliases>
    
        <environments default="mysql_mybatis">
            <environment id="mysql_mybatis">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <package name="com.viking.dao"/>
        </mappers>
    </configuration>
    
  5. 准备好单元测试类备用

    /**
     * Mybatis的注解开发功能测试--简单的CURD操作
     */
    public class MybatisAnnotationTest {
        private InputStream is;
        private SqlSession session;
        private IUserDao dao;
    
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            session = factory.openSession();
            dao = session.getMapper(IUserDao.class);
        }
        @After
        public void destory() throws IOException {
            session.close();
            is.close();
        }
    }
    
2.2 查询全部用户
  1. 在映射器接口IUserDao中增加方法

    @Select("select * from user")
    List<User> queryAll();
    
  2. 在测试类MybatisAnnotationTest中编写测试代码

    @Test
    public void testQueryAll(){
        List<User> users = dao.queryAll();
        for (User user : users) {
            System.out.println(user);
        }
    }
    
2.3 根据主键查询一个用户
  1. 在映射器接口IUserDao中增加方法

    @Select("select * from user where id = #{id}")
    User findById(Integer id);
    
  2. 在测试类MybatisAnnotationTest中编写测试代码

    @Test
    public void testFindById(){
        User user = dao.findById(41);
        System.out.println(user);
    }
    
2.4 添加用户
  1. 在映射器接口IUserDao中增加方法

    @Insert("insert into user (id,username,birthday,sex,address) values (#{id},#{username},#{birthday},#{sex},#{address})")
    @SelectKey(
        statement = "select last_insert_id()", //查询最新主键值的SQL语句
        resultType = Integer.class,  //得到最新主键值的类型
        keyProperty = "id",  //得到最新主键值,保存到哪个属性里
        before = false  //是否在insert操作之前查询最新主键值
    )
    void save(User user);
    
  2. 在测试类MybatisAnnotationTest中编写测试代码

    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("小红");
        user.setSex("女");
        user.setAddress("中国钓鱼岛");
        user.setBirthday(new Date());
    
        System.out.println("保存之前:" + user);
        dao.save(user);
        session.commit();
        System.out.println("保存之后:" + user);
    }
    
2.5 修改用户
  1. 在映射器接口IUserDao中增加方法

    @Update("update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}")
    void edit(User user);
    
  2. 在测试类MybatisAnnotationTest中编写测试代码

    @Test
    public void testEdit(){
        User user = dao.findById(57);
        user.setAddress("广州");
    
        dao.edit(user);
        session.commit();
    }
    
2.6 删除用户
  1. 在映射器接口IUserDao中增加方法

    @Delete("delete from user where id = #{id}")
    void delete(Integer id);
    
  2. 在测试类MybatisAnnotationTest中编写测试代码

    @Test
    public void testDelete(){
        dao.delete(57);
        session.commit();
    }
    
2.7 JavaBean属性名和字段名不一致的情况处理
  1. 创建JavaBean: User2

    public class User2 {
        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;
        }
    
        @Override
        public String toString() {
            return "User2{" +
                    "userId=" + userId +
                    ", username='" + username + '\'' +
                    ", userBirthday=" + userBirthday +
                    ", userSex='" + userSex + '\'' +
                    ", userAddress='" + userAddress + '\'' +
                    '}';
        }
    }
    
  2. 在映射器接口IUserDao中增加方法

    @Select("select * from user")
    @Results({
        @Result(property = "userId", column = "id", id = true),
        @Result(property = "username", column = "username"),
        @Result(property = "userBirthday", column = "birthday"),
        @Result(property = "userSex", column = "sex"),
        @Result(property = "userAddress", column = "address")
    })
    List<User2> queryAllUser2();
    
  3. 在测试类MybatisAnnotationTest中编写测试代码

    @Test
    public void testQueryAllUser2(){
        List<User2> user2List = dao.queryAllUser2();
        for (User2 user2 : user2List) {
            System.out.println(user2);
        }
    }
    

3. 使用注解实现复杂关系操作-多表关联查询

3.1 准备Mybatis环境
  1. 创建Maven的Java项目,设置好坐标,引入Mybatis的依赖

  2. 创建JavaBean

    注意:Account中要有User的引用,User中要有Account的集合

    public class User {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        private List<Account> 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;
        }
    
        public List<Account> getAccounts() {
            return accounts;
        }
    
        public void setAccounts(List<Account> accounts) {
            this.accounts = accounts;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    ", accounts=" + accounts +
                    '}';
        }
    }
    
    public class Account {
        private Integer id;
        private Integer uid;
        private Double money;
    
        private 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;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", uid=" + uid +
                    ", money=" + money +
                    ", user=" + user +
                    '}';
        }
    }
    
  3. 创建映射器接口IUserDao和IAccountDao,备用

    public interface IAccountDao {
    }
    
    public interface IUserDao {
    }
    
  4. 准备好核心配置文件,配置好别名和映射器

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <package name="com.viking.bean"/>
        </typeAliases>
    
        <environments default="mysql_mybatis">
            <environment id="mysql_mybatis">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <package name="com.viking.dao"/>
        </mappers>
    </configuration>
    
  5. 准备好单元测试类备用

    /**
     *  Mybatis的注解开发--复杂的注解开发,多表关联查询测试类
     */
    public class MybatisComplexAnnotationTest {
        private InputStream is;
        private SqlSession session;
        private IUserDao userDao;
        private IAccountDao accountDao;
    
        @Before
        public void init() throws IOException {
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            session = factory.openSession();
            userDao = session.getMapper(IUserDao.class);
            accountDao = session.getMapper(IAccountDao.class);
        }
        @After
        public void destory() throws IOException {
            session.close();
            is.close();
        }
    }
    
3.2 一对一(多对一)关联查询,实现懒加载

需求:查询帐号信息,及其关联的用户信息

  1. 修改映射器接口IUserDao,增加方法findById(供关联查询时使用)

    @Select("select * from user where id = #{id}")
    User findById(Integer id);
    
  2. 创建JavaBean:Account

    注意:Account中要有User的引用,前边已经准备好

  3. 修改映射器接口IAccountDao,增加方法

    @Select("select * from account where id = #{id}")
    @Results({
        @Result(property = "id", column = "id", id = true),
        @Result(property = "uid", column = "uid"),
        @Result(property = "money", column = "money"),
        @Result(
            property = "user",
            javaType = User.class,
            column = "uid",
            one = @One(
                //一对一关联查询,调用select配置的statement,得到关联的User对象
                select = "com.viking.dao.IUserDao.findById",
                //FetchType.LAZY 表示要使用延迟加载
                fetchType = FetchType.LAZY
            )
        )
    })
    Account findById(Integer id);
    
  4. @Select("select * from account where id = #{id}")
    @Results({
        @Result(property = "id", column = "id", id = true),
        @Result(property = "uid", column = "uid"),
        @Result(property = "money", column = "money"),
        @Result(
            property = "user",
            javaType = User.class,
            column = "uid",
            one = @One(
                select = "com.viking.dao.IUserDao.findById",
                fetchType = FetchType.LAZY
            )
        )
    })
    Account findById(Integer id);
    
  5. 编写测试代码

    @Test
    public void testOne2One(){
        Account account = accountDao.findById(1);
        System.out.println(account.getId() + ", "+ account.getMoney());
        
        //如果不执行下面这行代码,Mybatis不会发起查询用户的SQL
        System.out.println(account.getUser());
    }
    
3.3 一对多(多对多)关联查询,实现懒加载

需求:查询用户信息,及其关联的帐号信息

  1. 修改映射器IAccountDao,增加方法findAccountsByUid(供关联查询时使用)

    @Select("select * from account where uid = #{uid}")
    List<Account> findAccountsByUid(Integer uid);
    
  2. 修改JavaBean:User

    注意:User中需要有Account的集合,前边已经准备好

  3. 修改映射器接口IUserDao,增加方法

    /**
         * 查询用户信息,及其关联的帐号信息集合
         * @param id
         * @return
         */
    @Select("select * from user where id = #{id}")
    @Results({
        @Result(property = "id",column = "id",id = true),
        @Result(property = "username",column = "username"),
        @Result(property = "birthday",column = "birthday"),
        @Result(property = "sex",column = "sex"),
        @Result(property = "address",column = "address"),
        @Result(
            property = "accounts",
            javaType = List.class, //注意,这里是List.class,而不是Account.class
            column = "id",
            many = @Many(
                //一对多关联查询,调用select对应的statement,得到帐号集合
                select = "com.viking.dao.IAccountDao.findAccountsByUid",
                //FetchType.LAZY 表示要使用延迟加载
                fetchType = FetchType.LAZY
            )
        )
    })
    User findUserAccountsById(Integer id);
    
  4. 编写测试代码

    @Test
    public void testOne2Many(){
        User user = userDao.findUserAccountsById(41);
        System.out.println(user.getUsername()+", " + user.getAddress());
        
        //如果不执行下面这行代码,Mybatis不会发起查询帐号的SQL语句
        System.out.println(user.getAccounts());
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值