栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Java从零到架构师第③季】【10】MyBatis-实现DAO层

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Java从零到架构师第③季】【10】MyBatis-实现DAO层


持续学习&持续更新中…

守破离


【Java从零到架构师第③季】【10】MyBatis-实现DAO层
    • MyBatis实现DAO层的三种方案
    • 准备:JavaBean、DAO接口、映射XML
    • 方法一:DAO实现类+映射XML
    • 方法二:getMapper+映射XML
    • 方法三:getMapper+注解
    • XML和注解混合使用
    • XML与注解的比较
    • 常用注解
        • @SelectKey
        • @Options:
        • @Param
        • @CacheNamespace
        • @Results、@Result、@One、@Many
        • @ConstructorArgs、@Arg
    • 使用注解进行多表查询
    • 注意和一些建议
    • 参考

MyBatis实现DAO层的三种方案

准备:JavaBean、DAO接口、映射XML
  • bean:Skill

  • dao:SkillDao

  • 映射xml:skill.xml
	
	    SELECT id, name, level, created_time FROM skill
	
	
	    INSERT INTO skill(name, level) VALUES(#{name}, #{level})
	
	
	    DELETE FROM skill WHERe id = #{id}
	
	
	    UPDATE skill SET name = #{name}, level = #{level} WHERe id = #{id}
	
	
	
方法一:DAO实现类+映射XML
  • dao实现类
public class SkillDaoImpl implements SkillDao {
    @Override
    public boolean add(Skill skill) {
        try (SqlSession session = MyBatises.openSession(true)) {
            return session.insert("skill.add", skill) > 0;
        }
    }

    @Override
    public boolean remove(Integer id) {
        try (SqlSession session = MyBatises.openSession(true)) {
            return session.delete("skill.remove", id) > 0;
        }
    }

    @Override
    public boolean update(Skill skill) {
        try (SqlSession session = MyBatises.openSession(true)) {
            return session.update("skill.update", skill) > 0;
        }
    }

    @Override
    public Skill get(Integer id) {
        try (SqlSession session = MyBatises.openSession()) {
            return session.selectOne("skill.get", id);
        }
    }

    @Override
    public List list() {
        try (SqlSession session = MyBatises.openSession()) {
            return session.selectList("skill.list");
        }
    }
}
  • 测试类
public class SkillDaoTest {

    @Test
    public void add() {
        SkillDao dao = new SkillDaoImpl();
        final Skill skill = new Skill("learn programming", 10086);
        Assert.assertTrue(dao.add(skill));
        System.out.println(skill.getId());
    }

    @Test
    public void remove() {
        SkillDao dao = new SkillDaoImpl();
        Assert.assertTrue(dao.remove(41));
    }

    @Test
    public void update() {
        SkillDao dao = new SkillDaoImpl();
        Skill skill = new Skill("666", 666);
        skill.setId(42);
        Assert.assertTrue(dao.update(skill));
    }

    @Test
    public void get() {
        SkillDao dao = new SkillDaoImpl();
        System.out.println(dao.get(1).getName());
    }

    @Test
    public void list() {
        SkillDao dao = new SkillDaoImpl();
        List skills = dao.list();
        for (Skill skill : skills) {
            System.out.println(skill.getId() + "____" + skill.getName());
        }
    }

}
方法二:getMapper+映射XML


  • 一个XML映射文件下,标签的id不能重复,必须唯一。
  • 相应的,使用注解+DAO接口实现DAO层时,DAO接口中的方法名也不能重复,必须唯一。

  • 测试类
public class SkillDaoTest {

    @Test
    public void add() {
        try (final SqlSession session = MyBatises.openSession(true)) {
            SkillDao dao = session.getMapper(SkillDao.class);
            final Skill skill = new Skill("learn programming", 10086);
            Assert.assertTrue(dao.add(skill));
            System.out.println(skill.getId());
        }
    }

    @Test
    public void remove() {
        try (final SqlSession session = MyBatises.openSession(true)) {
            SkillDao dao = session.getMapper(SkillDao.class);
            Assert.assertTrue(dao.remove(45));
        }
    }

    @Test
    public void update() {
        try (final SqlSession session = MyBatises.openSession(true)) {
            SkillDao dao = session.getMapper(SkillDao.class);
            Skill skill = new Skill("666", 666);
            skill.setId(30);
            Assert.assertTrue(dao.update(skill));
        }
    }

    @Test
    public void get() {
        try (final SqlSession session = MyBatises.openSession()) {
            SkillDao dao = session.getMapper(SkillDao.class);
            System.out.println(dao.get(1).getName());
        }
    }

    @Test
    public void list() {
        try (final SqlSession session = MyBatises.openSession()) {
            SkillDao dao = session.getMapper(SkillDao.class);
            List skills = dao.list();
            for (Skill skill : skills) {
                System.out.println(skill.getId() + "____" + skill.getName());
            }
        }
    }

}
方法三:getMapper+注解

https://mybatis.org/mybatis-3/zh/java-api.html

  • mybatis-config.xml:
    
        
    
  • SkillDao:
public interface SkillDao {
    @Insert(value="INSERT INTO skill(name, level) VALUES(#{name}, #{level})")
    boolean add(Skill skill);

    @Delete("DELETE FROM skill WHERe id = #{id}")
    boolean remove(Integer id);

    @Update("UPDATE skill SET name = #{name}, level = #{level} WHERe id = #{id}")
    boolean update(Skill skill);

    @Select("SELECT id, name, level, created_time FROM skill WHERe id = #{id}")
    Skill get(Integer id);

    @Select("SELECT id, name, level, created_time FROM skill")
    List list();
}
  • 测试类:和方法二的测试类一样
XML和注解混合使用

注解的功能没有XML强大,有时候满足不了需求,所以可以XML+注解混合使用

比如:上面方法三单独使用注解时,插入一条记录(SkillDao.add)直接获取不到id,只能使用XML的useGeneratedKeys、keyProperty来获取id,因此,考虑XML和注解混合使用:

PS:其实可以使用@SelectKey注解获取新插入对象的id,这儿只是想演示一下XML和注解如何混合使用而已

  • mybatis-config.xml

    1. 注意顺序:class必须放在resource之上
    2. 不能使用package标签:
    
        
        
    
  • SkillDao接口
public interface SkillDao {
    boolean add(Skill skill);

    @Delete("DELETE FROM skill WHERe id = #{id}")
    boolean remove(Integer id);

    @Update("UPDATE skill SET name = #{name}, level = #{level} WHERe id = #{id}")
    boolean update(Skill skill);

    @Select("SELECT id, name, level, created_time FROM skill WHERe id = #{id}")
    Skill get(Integer id);

    @Select("SELECT id, name, level, created_time FROM skill")
    List list();
}
  • skill.xml:



    
        INSERT INTO skill(name, level) VALUES(#{name}, #{level})
    


  • 测试类:同方法二的测试类
XML与注解的比较

MJ老师的忠告:以后学习Spring等框架的时候首先要牢牢掌握XML形式的使用方法,因为注解形式的用法是基于XML的,是先有XML再有注解的。

  • XML形式书写起来更清晰、简洁、方便
  • XML可以实现复杂的操作,功能比注解强大(比如:一次性查出所有内容、批量处理…,这些使用XML实现更方便)
  • 使用XML可以更好的维护代码,不推荐使用注解来实现。

  • .java文件部署到项目时会被编译为.class文件,.xml文件会直接被copy过去。
  • 使用注解,就相当于把SQL语句写在Java代码中了,最终这些SQL会被编译为class字节码文件,字节码肯定不方便修改,只能修改Java代码然后重新编译生成字节码文件,然后将其再部署到服务器。
  • 而使用XML映射文件配置SQL,则修改起来比较方便,不用修该Java代码,直接修改xml文件即可。

  • 使用注解看起来很简洁,但项目较大时,XML文件则看起来更直观。
  • 注解比较时髦,适合简单的小型项目
常用注解

https://mybatis.org/mybatis-3/zh/java-api.html

@SelectKey
  • XML形式:
    
        INSERT INTO skill(name, level) VALUES (#{name}, #{level})
        
            SELECT LAST_INSERT_ID()
        
    
  • 注解形式
    @Insert("INSERT INTO skill(name, level) VALUES(#{name}, #{level})")
    @SelectKey(
            statement = "SELECT LAST_INSERT_ID()",
            resultType = Integer.class,
            keyProperty = "id",
            before = false
    )
    boolean add(Skill skill);
@Options:

@Options中可以配置很多属性:

  • XML形式:
    
        INSERT INTO skill(name, level) VALUES(#{name}, #{level})
    
  • 注解形式:
    @Insert("INSERT INTO skill(name, level) VALUES(#{name}, #{level})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    boolean add(Skill skill);
@Param

如果DAO接口有多个形参的话,比如下面这样:

方法名在编译之后就不存在了,会被编译为:

MyBatis是找不到正确的参数的,因此必须使用@Param注解:

    @Select("SELECT id, name, level, created_time FROM skill LIMIT #{start}, #{size}")
    List listPage(@Param("start") Integer start,@Param("size") Integer size);
@CacheNamespace

对应标签,用来设置二级缓存

二级缓存是namespace级别的

//@CacheNamespace()
@CacheNamespace(readWrite = false, eviction = FifoCache.class)
public interface SkillDao {
    // ...
    @Select("SELECT id, name, level, created_time FROM skill WHERe id = #{id}")
    @Options(useCache = false)
    Skill get(Integer id);
}


    
    
    
        SELECT id, name, level, created_time FROM skill WHERe id = #{id}
    

@Results、@Result、@One、@Many
  • @Results对应、@ResultMap用来引用已经写好的@Results

  • @Result对应

  • @One对应、@Many对应

    xml代码:

        
            SELECT id, no, amout FROM bank_card WHERe person_id = #{personId}
        
    
        
             WHERe id = #{id}
        
        
    

    注解代码:

    	public interface IdCardDao {
    	    @Select("SELECT id, no, address FROM id_card WHERe person_id = #{personId}")
    	    IdCard getByPersonId(Integer personId);
    	}
    
    	public interface BankCardDao {
    	    @Select("SELECT id, no, amout FROM bank_card WHERe person_id = #{personId}")
    	    List listByPersonId(Integer personId);
    	}
    
    	public interface JobDao {
    	    @Select("SELECT id, name, duty FROM job " +
    	            "JOIN person_job " +
    	            "ON person_job.job_id = id AND person_job.person_id = #{personId}")
    	    List listByPersonId(Integer personId);
    	}
    
    	public interface PersonDao {
    	    @Select("SELECT id, name FROM person WHERe id = #{id}")
    	    @Results(
    	            id = "rmListPerson",
    	            value={
    	                    @Result(property = "id", column = "id", id = true),
    	                    @Result(property = "name", column = "name"),
    	                    @Result(
    	                            property = "idCard",
    	                            column = "id",
    	                            one = @One(select = "programmer.lp.dao.IdCardDao.getByPersonId")
    	                    ),
    	                    @Result(
    	                            property = "bankCards",
    	                            column = "id",
    	                            many = @Many(select = "programmer.lp.dao.BankCardDao.listByPersonId")
    	                    ),
    	                    @Result(
    	                            property = "jobs",
    	                            column = "id",
    	                            many = @Many(select = "programmer.lp.dao.JobDao.listByPersonId")
    	                    )
    	            }
    	    )
    	    Person get(Integer id);
    	
    	    @Select("SELECT id, name FROM person")
    	    @ResultMap("rmListPerson")
    	    List list();
    	}
    

    如果想要延迟加载的话:

@ConstructorArgs、@Arg

@ConstructorArgs对应,@Arg对应

方式一:

    
        
            
            
        
    
    
        SELECT * FROM skill
    
    @Select("SELECT id, name, level, created_time FROM skill")
    @ConstructorArgs({
            @Arg(column = "name", name = "name"),
            @Arg(column = "level", name = "level")
    })
    List list();

方式二:

    
        
            
            
        
    
    
        SELECT * FROM skill
    
    @Select("SELECT id, name, level, created_time FROM skill")
    @ConstructorArgs({
            @Arg(column = "name", javaType = String.class),
            @Arg(column = "level", javaType = Integer.class)
    })
    List list();
使用注解进行多表查询
  • 使用注解进行多表查询时,不能使用如下方法:

  • 只能使用这种方法:

  • 如果要想延迟加载的话:

    1. 开启全局延迟加载:开启全局延迟加载后,所有设置了select属性的关联对象(association、collection)都会开启延迟加载
    	
    
    1. 挨个配置延迟加载:

  • 注解代码:与上面常用注解中讲@Results、@Result、@One、@Many的代码相同。
注意和一些建议
  • 很多编程语言中,在编译方法时,默认不会保留形参变量名,而是会将其编译为arg1、arg2、arg3…或者param1、param2、param3…之类的东西
  • 当然,你也可以通过设置编译器的编译参数这种方式,让其编译时保留形参变量名。

  • MJ老师的忠告:以后学习Spring等框架的时候首先要牢牢掌握XML形式的使用方法,因为注解形式的用法是基于XML的,是先有XML再有注解的。

  • 查询时设置标签有助于提升性能

  • 一个XML映射文件下,标签的id不能重复,必须唯一。
  • 相应的,使用注解+DAO接口实现DAO层时,DAO接口中的方法名也不能重复,必须唯一。

  • 注解中只有一个value值时,可以省略value不写:

        @Delete(value="DELETE FROM skill WHERe id = #{id}")
        boolean remove(Integer id);
    
        @Delete("DELETE FROM skill WHERe id = #{id}")
        boolean remove(Integer id);
    

  • 当控制台有红色警告MySQL的SSL相关时,在打开数据库的时候,在url后面添加上?useSSL="false"即可。

    url=jdbc:mysql://localhost:3306/test_mybatis?useSSL=false
    

  • SkillDao的add、remove、update方法都只操作一条SQL语句,不涉及事务管理,因此可以自动提交事务。

  • 批量处理SQL也是一条语句(如下会生成:INSERT INTO skill(name, level) VALUES (?, ?) , (?, ?) , (?, ?) , (?, ?) , (?, ?)),也可直接提交事务,不用手动进行事务管理,如果出现异常则就插入不成功,不会更新数据到数据库中。

        
            INSERT INTO skill(name, level) VALUES
            
                (#{skill.name}, #{skill.level})
            
        
    
        public void adds() {
            try (final SqlSession session = MyBatises.openSession(true)) {
                SkillDao dao = session.getMapper(SkillDao.class);
                List lists = new ArrayList<>();
                Skill skill = new Skill("learn 1", 1001); lists.add(skill);
                skill = new Skill("learn 2", 1002); lists.add(skill);
                skill = new Skill(null, null); lists.add(skill); // 这两个字段被约束为NOT NULL,因此会出现异常,数据库肯定插入不成功
                skill = new Skill("learn 3", 1003); lists.add(skill);
                skill = new Skill("learn 4", 1004); lists.add(skill);
                Assert.assertTrue(dao.adds(lists));
                for (Skill s : lists) {
                    System.out.println(s.getId());
                }
            }
        }
    

  • SqlSession的 T getMapper(Class type);方法会生成DAO接口的代理对象,其中使用了代理模式。
参考

小码哥-李明杰: Java从0到架构师③进阶互联网架构师.


本文完,感谢您的关注支持!


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/694074.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号