MyBatis 关联查询--逆向工程--实训20191030

mac2024-01-24  39

4 关联映射

一对一 人 +IdCard

public class Student { private Integer id; private String name; private Card card;//关联属性 StudentMapper.xml <mapper namespace="studentNamespace"> <resultMap type="cn.atcast.javaee.mybatis.one2one.Student" id="studentMap"> <id property="id" column="sid"></id> <result property="name" column="sname"></result> <!-- association :关联 --> <association property="card" resultMap="cardNamespace.cardMap"></association> </resultMap> <!-- 查询1号学生的信息 --> <select id="findById" parameterType="int" resultMap="studentMap"> select s.sid,s.sname,c.cid,c.cnum from students s INNER JOIN cards c on s.scid=c.cid where s.sid=#{id} </select> <!-- 按学生名查询 --> <select id="findByName" parameterType="string" resultMap="studentMap"> select s.sid,s.sname,c.cid,c.cnum from students s INNER JOIN cards c on s.scid=c.cid where s.sname=#{name} </select> </mapper> public class Card { private Integer id; private String num; private Student student; //双向 CardMapper.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="cardNamespace"> <resultMap type="cn.atcast.javaee.mybatis.one2one.Card" id="cardMap"> <id property="id" column="cid"/> <result property="num" column="cnum"></result> </resultMap> </mapper>

/** *工具类MybatisUtil */ 首先回顾一下我们使用Mybatis来操作数据库的步骤:

1、加载核心配置文件sqlMapConfig.xml(名字可以自己随便取);

2、通过 SqlSessionFactoryBuilder来得到SqlSessionFactory ;

3、通过SqlSessionFactory 来创建SqlSession;

4、通过SqlSession来调用增删该查的方法或者获取Mapper对象来调用相应的方法去操作数据库;

5、提交事务;

6、关闭SqlSession。

但是每次操作数据库都要重复上述步骤,为什么不像封装jdbcUtil一样封装一个工具类呢?

import java.io.IOException; import java.io.Reader; import java.sql.Connection; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MybatisUtil { // 将SqlSession创建出来,存放到Threadlocal中,需要时再从中取出 private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>(); private static SqlSessionFactory sqlSessionFactory; /** * 加载位于src/mybatis.xml配置文件 */ static{ try { // InputStream 对象接收也可以 Reader reader = Resources.getResourceAsReader("mybatis.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 禁止外界通过new方法创建 *初始化sqlSessionFactory,只需要一个对象,所以是静态的 */ private MybatisUtil(){} /** * 获取SqlSession */ public static SqlSession getSqlSession(){ //从当前线程中获取SqlSession对象 SqlSession sqlSession = threadLocal.get(); //如果SqlSession对象为空 if(sqlSession == null){ //在SqlSessionFactory非空的情况下,获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(); //将SqlSession对象与当前线程绑定在一起 threadLocal.set(sqlSession); } //返回SqlSession对象 return sqlSession; } /** * 关闭SqlSession与当前线程分开 */ public static void closeSqlSession(){ //从当前线程中获取SqlSession对象 SqlSession sqlSession = threadLocal.get(); //如果SqlSession对象非空 if(sqlSession != null){ //关闭SqlSession对象 sqlSession.close(); //分开当前线程与SqlSession对象的关系,目的是让GC尽早回收 threadLocal.remove();//threadLocal.set(null); } } /** * 测试 */ public static void main(String[] args) { Connection conn = MybatisUtil.getSqlSession().getConnection(); System.out.println(conn!=null?"连接成功":"连接失败"); } }

测试类

public class StudentCardDao { /** * 查询1号学生的信息 * @param id 表示学生的编号 */ public Student findById(int id) throws Exception{ SqlSession sqlSession = null; try{ sqlSession = MybatisUtil.getSqlSession(); return sqlSession.selectOne("studentNamespace.findById",id); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } /** * 查询"哈哈"学生的信息 * @param name 表示学生的姓名 */ public Student findByName(String name) throws Exception{ SqlSession sqlSession = null; try{ sqlSession = MybatisUtil.getSqlSession(); return sqlSession.selectOne("studentNamespace.findByName",name); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } public static void main(String[] args) throws Exception{ StudentCardDao dao = new StudentCardDao(); Student s = dao.findById(1); System.out.println(s.getId()+":"+s.getName()+":"+s.getCard().getId()+":"+s.getCard().getNum()); System.out.println("-------------------------------"); s = dao.findByName("哈哈"); System.out.println(s.getName()+"的身份证号码为:" + s.getCard().getNum()); } }

4.2 一对多映射【班级与学生】

/**

学科(单方) */ public class Grade { private Integer id; private String name; //学科就是系 private List<Student> studentList = new ArrayList<Student>();//关联属性 public Grade(){} ..set/get省略 } GradeMapper.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="gradeNamespace"> <resultMap type="cn.atcast.javaee.mybatis.one2many.Grade" id="gradeMap"> <id property="id" column="gid"></id> <result property="name" column="gname"></result> <!-- <collection property="studentList" resultMap="studentNamespace.studentMap"></collection> 不写也可以拿到--> </resultMap> <!-- 根据用户名去查班级 --> <select id="findByName" parameterType="string" resultMap="gradeMap"> select g.gname from students s INNER JOIN grades g on s.sgid=g.gid and s.sname=#{name} </select> </mapper>

/**

学生(多方) */ public class Student { private Integer id; private String name; private Grade grade;//关联属性 public Student(){} ..set/get省略 } StudentMapper.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="studentNamespace"> <resultMap type="cn.atcast.javaee.mybatis.one2many.Student" id="studentMap"> <id property="id" column="sid"></id> <result property="name" column="sname"></result> <association property="grade" resultMap="gradeNamespace.gradeMap"></association> </resultMap> <select id="findAllByName" parameterType="string" resultMap="studentMap"> select s.sid,s.sname from students s INNER JOIN grades g on s.sgid=g.gid and g.gname=#{name} </select> </mapper>

/** 测试

{持久层} */ public class GradeStudentDao { /** * 查询java学科有哪些学生信息 * @param name 表示学科名 */ public List<Student> findAllByName(String name) throws Exception{ SqlSession sqlSession = null; try{ sqlSession = MybatisUtil.getSqlSession(); return sqlSession.selectList("studentNamespace.findAllByName",name); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } /** * 查询哈哈是哪个学科的 * @param name 表示学生姓名 */ public Grade findByName(String name) throws Exception{ SqlSession sqlSession = null; try{ sqlSession = MybatisUtil.getSqlSession(); return sqlSession.selectOne("gradeNamespace.findByName",name); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } public static void main(String[] args) throws Exception{ GradeStudentDao dao = new GradeStudentDao(); List<Student> studentList = dao.findAllByName("java"); System.out.println("java学科有"+studentList.size()+"个学生,它们信息如下:"); for(Student s : studentList){ System.out.println(s.getId()+":"+s.getName()); } System.out.println("-----------------------------------------------------------"); Grade grade = dao.findByName("哈哈"); System.out.println("哈哈是"+grade.getName()+"学科的"); System.out.println("-----------------------------------------------------------"); grade = dao.findByName("呵呵"); System.out.println("呵呵是"+grade.getName()+"学科的"); } }

4.3 多对多映射【学生与课程】

/**

学生(多方) */ public class Student { private Integer id; private String name; private List<Course> courseList = new ArrayList<Course>();//关联属性 public Student(){}

StudentMapper.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="studentNamespace"> <resultMap type="cn.atcast.javaee.mybatis.many2many.Student" id="studentMap"> <id property="id" column="sid"/> <result property="name" column="sname"/> </resultMap> <select id="findAllByCourseName" parameterType="string" resultMap="studentMap"> select s.sname from students s inner join middles m on s.sid = m.msid inner join courses c on m.mcid = c.cid and c.cname = #{name} </select> </mapper>

/**

课程(多方) */ public class Course { private Integer id; private String name; private List<Student> studentList = new ArrayList<Student>();//关联属性 public Course(){}

CourseMapper.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="courseNamespace"> <resultMap type="cn.atcast.javaee.mybatis.many2many.Course" id="courseMap"> <id property="id" column="cid"/> <result property="name" column="cname"/> </resultMap> <!-- 查询哈哈选学了哪些课程 --> <select id="findAllByName" parameterType="string" resultMap="courseMap"> select c.cid,c.cname from students s inner join middles m on s.sid = m.msid inner join courses c on m.mcid = c.cid and s.sname = #{name} </select> </mapper>

StudentCourseDao.java

public class StudentCourseDao { /** * 查询哈哈选学了哪些课程 * @param name 表示学生的姓名 */ public List<Course> findAllByName(String name) throws Exception{ SqlSession sqlSession = null; try{ sqlSession = MybatisUtil.getSqlSession(); return sqlSession.selectList("courseNamespace.findAllByName",name); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } /** * 查询java课程有哪些学生选修 * @param name 表示学生的课程 */ public List<Student> findAllByCourseName(String name) throws Exception{ SqlSession sqlSession = null; try{ sqlSession = MybatisUtil.getSqlSession(); return sqlSession.selectList("studentNamespace.findAllByCourseName",name); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ MybatisUtil.closeSqlSession(); } } public static void main(String[] args) throws Exception{ StudentCourseDao dao = new StudentCourseDao(); List<Course> courseList = dao.findAllByName("哈哈"); System.out.print("哈哈选学了" + courseList.size()+"个课程,分别是:"); for(Course c : courseList){ System.out.print(c.getName()+" "); } System.out.println("\n---------------------"); List<Student> studentList = dao.findAllByCourseName("android"); System.out.println("选修了android课程的学生有"+studentList.size()+"个,分别是:"); for(Student s : studentList){ System.out.print(s.getName()+" "); } } }

6 Mybatis逆向工程

使用官方网站的mapper自动生成工具mybatis-generator-core-1.3.2来生成po类和mapper映射文件。

作用:mybatis官方提供逆向工程,可以使用它通过数据库中的表来自动生成Mapper接口和映射文件(单表增删改查)和Po类.

导入的jar包有:

6.1 第一步:mapper生成配置文件:

在generatorConfig.xml中配置mapper生成的详细信息,注意改下几点: 1、 添加要生成的数据库表 2、 po文件所在包路径 3、 mapper文件所在包路径

配置文件如下:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="caigouTables" targetRuntime="MyBatis3"> <commentGenerator> <!-- 是否去除自动生成的注释 true:是 : false:--> <property name="suppressAllComments" value="true" /> </commentGenerator> <!--数据库连接的信息:驱动类、连接地址、用户名、密码 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root"> </jdbcConnection> <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:orcl" userId="scott" password="tiger"> </jdbcConnection> --> <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer true,把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal --> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- targetProject:生成PO类的位置 --> <javaModelGenerator targetPackage="cn.atcast.pojo" targetProject=".\src"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> <!-- 从数据库返回的值被清理前后的空格 --> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- targetPackage:mapper映射文件生成的位置 --> <sqlMapGenerator targetPackage="cn.atcast.mapper" targetProject=".\src"> <property name="enableSubPackages" value="false" /> </sqlMapGenerator> <!-- targetPackage:mapper接口的生成位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="cn.atcast.mapper" targetProject=".\src"> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <!-- 指定表 --> <table schema="" tableName="user" /> <table schema="" tableName="orders" /> </context> </generatorConfiguration>

6.2 第二步:使用java类生成mapper文件:

GeneratorSqlmap.java

import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.mybatis.generator.api.MyBatisGenerator; import org.mybatis.generator.config.Configuration; import org.mybatis.generator.config.xml.ConfigurationParser; import org.mybatis.generator.exception.XMLParserException; import org.mybatis.generator.internal.DefaultShellCallback; public class GeneratorSqlmap { public void generator() throws Exception{ List<String> warnings = new ArrayList<String>(); boolean overwrite = true; File configFile = new File("generatorConfig-base.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); } public static void main(String[] args) throws Exception { try { GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap(); generatorSqlmap.generator(); } catch (Exception e) { e.printStackTrace(); } } }

6.3 第三步:拷贝生成的mapper文件到工程中指定目录中

6.3.1 Mapper.xml Mapper.xml的文件拷贝至mapper目录内 6.3.2 Mapper.java Mapper.java的文件拷贝至mapper 目录内

注意:mapper xml文件和mapper.java文件在一个目录内且文件名相同。

6.4 第四步Mapper接口测试

学会使用mapper自动生成的增、删、改、查方法。 cn.atcast.mapper/UserMapper.java

package cn.atcast.test; import java.io.InputStream; 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.Before; import org.junit.Test; import cn.atcast.mapper.UserMapper; import cn.atcast.pojo.User; public class UserMapperTest { private SqlSessionFactory factory; // 作用:在测试方法前执行这个方法 @Before public void setUp() throws Exception { String resource = "SqlMapConfig.xml"; // 通过流将核心配置文件读取进来 InputStream inputStream = Resources.getResourceAsStream(resource); // 通过核心配置文件输入流来创建会话工厂 factory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindUserById() throws Exception { SqlSession openSession = factory.openSession(); UserMapper mapper = openSession.getMapper(UserMapper.class); User user=mapper.selectByPrimaryKey(1); System.out.println(user); } }

6.5 逆向工程注意事项

6.5.1 Mapper文件内容不覆盖而是追加 XXXMapper.xml文件已经存在时,如果进行重新生成则mapper.xml文件内容不被覆盖而是进行内容追加,结果导致mybatis解析失败。 解决方法:删除原来已经生成的mapper xml文件再进行生成。 Mybatis自动生成的po及mapper.java文件不是内容而是直接覆盖没有此问题。

7 Hibernate与Mybatis对比

首先简单介绍下两者的概念 Hibernate :Hibernate 是当前最流行的ORM框架,对数据库结构提供了较为完整的封装。 Mybatis:Mybatis同样也是非常流行的ORM框架,主要着力点在于POJO 与SQL之间的映射关系。 其次具体从几个方面说一下两者的区别: 1.两者最大的区别 针对简单逻辑,Hibernate和MyBatis都有相应的代码生成工具,可以生成简单基本的DAO层方法。 针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。 2.开发难度对比 Hibernate的开发难度要大于Mybatis。主要由于Hibernate比较复杂、庞大,学习周期较长。 而Mybatis则相对简单一些,并且Mybatis主要依赖于sql的书写,让开发者感觉更熟悉。 3.sql书写比较 Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。不过没有自己的日志统计,所以要借助log4j来记录日志。 Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。不过Hibernate具有自己的日志统计。 4.数据库扩展性比较 Mybatis由于所有SQL都是依赖数据库书写的,所以扩展性,迁移性比较差。 Hibernate与数据库具体的关联都在XML中,所以HQL对具体是用什么数据库并不是很关心。 5.缓存机制比较 相同点:Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。 不同点:Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。 MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。 两者比较:因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。 而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。 6.总结 Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。 而MyBatis的优势是MyBatis可以进行更为细致的SQL优化,可以减少查询字段,并且容易掌握。 Hibernate的优势是DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

最新回复(0)