问题?mybatis的使用 Mybatis和hibernate的区别 EJB框架 mybatis环境搭建过程
一、EJB框架
(EJB重量级持久层,天然分布式,负载均衡) 但是不够灵活,不能充分适应业务。它实现的是多条件查询,如果使用EntityBean,做查询时,一种查询条件就得写一个sql。SessionBean新增,修改,删除交给EntityBean;多条件查询交SessionBean,正是因为这个原因才导致了EJB框架的消亡。
二、Mybatis定义
MyBatis 世界上流行最广泛的SQL 映射框架,由ClintonBegin在2002 年创建,iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。其后,捐献给了Apache基金会,成立了iBatis 项目。2010 年5 月,将代码库迁致Google Code,并更名为MyBatis。
它和hibernate的概念差不多,都是基于JDBC开发的框架,不过它与hibernate最重要的一个区别是,它是基于jdbc轻量级的封装。
三、Mybatis和hibernate的区别(面试)
1.区别
Hibernate—>java面向对象盛行时期,将整个开发设计过程全部面向对象开发,全ORM。
iBatis,维持原有的编程方式,前面部分按面向对象思考和设计,持久层时使用sql语句,面向过程。
1) hibernate,将hql语句转为sql“Sql无法优化",这方面在复杂大型项目,—>性能就不行了(针对中小型项目)
2) Hibernate通过反射,性能很低
3) Ibatis就是基于jdbc轻量级封装,还是使用sql。性能比较高。半OR
四、mybatis环境搭建过程
1.开发步骤
2.环境搭建(jar包)
jar包下载(包括核心包及依赖包)点击下载链接
mybatis-3.2.2.jar 核心驱动
(以下为依赖包)
asm-3.3.1.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
mysql-connector-java-5.1.26.jar 数据库驱动
3.搭建
(1).数据源配置 sqlMapConfig.xml配置文件文件(src下)
<span style="font-family:Microsoft YaHei;font-size:18px;"><?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> <typeAlias type="com.itcast.domain.User" alias="Person"></typeAlias> <!-- <typeAlias type="" alias=""/> --> </typeAliases> <!-- 配置数据源,事务,当然最后整合的时候就交给spring了,default:采用哪种方式 --> <environments default="test"> <!-- id:test/deploy 一种是测试的时候用,另外一种是发布的时候用 --> <environment id="test"> <!-- 事务:JDBC/MANAGED-这是自己管理,后期就是给spring管理,这里使用JDBC管理 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据源:POOLED/UNPOOLED/JNDI --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisEg1?charsetEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> <environment id="deploy"> <!-- 事务:JDBC/MANAGED-这是自己管理,后期就是给spring管理,这里使用JDBC管理 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据源:POOLED/UNPOOLED/JNDI --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisEg1?charsetEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!-- 映射文件mapper 这里和hibernate一样的,本文件就和hibernate.cfg.xml一样功能,MyBatis引用了hibernate的一些思想--> <mappers> <mapper resource="com/itcast/mapper/UserMapper.xml"/> </mappers> </configuration></span>
(2).建测试类qlSessionFactoryBuilder.builer()创建一个SqlSessionFactory,看看是否搭建成功
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.test; import java.io.IOException; 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.Test; public class TestMybatis { @Test public void init() throws IOException{ String resource = "sqlMapConfig.xml"; InputStream is = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); SqlSession session = factory.openSession(); } } </span>
出现红色警告是因为缺少日志文件log4j,但是我们jar包导入了,只是缺少它的配置文件log4j.properties,将它放入src下(即是classpath下),再次运行就没有这个红色警告了。
如果想看具体的底层操作sql语句,可以将日志文件中的log4j.rootLogger=DEBUG,,修改成DEBUG模式,具体效果看下面:
(3).通过SqlSessionFactory获取SqlSession,可以调用CRUD操作
建表:
创建实体类,包括setget方法
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.domain; import java.io.Serializable; public class User implements Serializable { private Integer id; private String username; private String password; private Integer age; private String remark; 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 String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + ", age=" + age + ", remark=" + remark + "]"; } } </span>
(4).和hibernate文件一样对应的又映射文件UserMapper.xml(不一定要在同一个包下,可以放在另外一个包下,这个在sqlMapConfig.xml中配置路径了)
这个映射文件非常重要,跟以往的映射文件大不相同,与hibernate 的不同在这里也开始体现,因为它的数据库底层操作,写sql语句也在这个文件当中。
<span style="font-family:Microsoft YaHei;font-size:18px;"><?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.itcast.mapper"> <!-- SQL片段:无疑是用来替换SQL部分的 --> <sql id="sql1">id,username,password,age,remark</sql> <!-- 最强大的功能,resultMap 描述中间 对象属性和结果集中的对应关系 id取个名字--> <resultMap type="com.itcast.domain.User" id="UserRM"> <!-- 主键 property:实体属性 column:结果集的字段名(没写,默认就是数据库列名) --> <id property="id" column="id"/> <!-- 普通字段 --> <result property="username" column="username"/> <result property="password" column="password"/> <result property="age" column="age"/> <result property="remark" column="remark"/> <!-- 关联关系 --> </resultMap> <!-- 查询 注意MyBatis中如果有些集合类型,只填写元素的类型 --> <!-- 可以随意取 resultType="List<User>" mybatis可以去猜类型,所以我们不需要这样写,直接写类 --> <!-- 可以写resultMap 值为之前配置好的resultMap的id值 --> <!-- 在这里和hibernate的映射文件就有很大的区别了 --> <!-- 执行结果,封装到对象结果集中,这个操作又底层操作完成 --> <select id="find" resultMap="UserRM"> select * from user </select> <!-- 查询一个值 --> <select id="getid" parameterType="int" resultType="Person"> select <include refid="sql1"/> from user where id = #{pid} </select> <!-- 带条件的查询 where 能自动去掉前面的and 或 or--> <select id="condition" resultMap="UserRM" parameterType="map"> select * from user <where> <if test="username!=null">username like #{username}</if> <if test="age!=null"><![CDATA[and age<=]]>#{age}</if> </where> <!-- 特殊字符处理 <![CDATA[ ]]> 转化成文本内容处理--> </select> <!-- 增加一个 parameterType:传过来的自然就是一个实体了,而#{}这里面的值必须是实体类中的属性--> <insert id="insert" parameterType="com.itcast.domain.User"> insert into user values (#{id},#{username},#{password},#{age},#{remark}) </insert> <!-- 删除一个 --> <delete id="deleteOne" parameterType="int"> delete from user where id=#{pid} </delete> <!-- 删除多条 --> <delete id="deleteMany" parameterType="int"> delete from user where id in <foreach collection="array" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete> <!-- 更新 --> <update id="update" parameterType="com.itcast.domain.User"> update user <!-- set id=#{id},username=#{username},password=#{password},age=#{age},remark=#{remark} --> <set> <if test="id!=null">id=#{id},</if> <if test="username!=null">username=#{username},</if> <if test="password!=null">password=#{password},</if> <if test="age!=null">age=#{age},</if> <if test="remark!=null">remark=#{remark}</if> </set> where id=#{id} </update> <!-- 获取记录条 --> <select id="count" resultType="int"> select count(*) from user </select> </mapper></span>
(5).建测试类
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.test; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.itcast.domain.User; import com.itcast.util.MyBatisSqlSessionFactiorUtil; public class sqlsessionFactoryTest extends MyBatisSqlSessionFactiorUtil{ // private SqlSessionFactory factory; /*在MyBatis中,SqlSessionFactory线程上是安全的,所以可以抽取出来单独初始化。但是sqlsession不是安全的*/ // @Before // public void test1() throws IOException{ // String resource = "sqlMapConfig.xml"; // InputStream inputStream = Resources.getResourceAsStream(resource); // factory = new SqlSessionFactoryBuilder().build(inputStream); // } /*select ALL*/ @Test public void selectAll() throws IOException{ SqlSession session= factory.openSession(); /*访问mapper中的方法 贵州:命名空间+id*/ List<User> userlist = session.selectList("com.itcast.mapper.find"); for(User user:userlist){ System.out.println(user.toString()); } } /*select one*/ @Test public void selectUser(){ SqlSession session = factory.openSession(); /*session.selectOne(arg0, arg1):查询一条数据的方法 第一个参数命名空间+id 第二个参数则是传过去的值*/ User user = session.selectOne("com.itcast.mapper.getid", 1); System.out.println(user.toString()); } /*select 带条件查询 发现这样的效率想当低啊*/ @Test public void selectUserCondtion(){ SqlSession session = factory.openSession(); /*session.selectOne(arg0, arg1):查询一条数据的方法 第一个参数命名空间+id 第二个参数则是传过去的值*/ Map<String, Object> maplist = new HashMap<String, Object>(); maplist.put("username", "li%"); maplist.put("age", 21); List<User> userlist = session.selectList("com.itcast.mapper.condition", maplist); for(User user: userlist){ System.out.println(user.toString()); } } /*insert one*/ @Test public void insetUser(){ SqlSession session = factory.openSession(); User user = new User(); user.setId(6); user.setUsername("lijun1"); user.setPassword("123456768"); user.setAge(2); user.setRemark("sdsdsd"); int i = session.insert("com.itcast.mapper.insert", user); if(i==1){ System.out.println("成功插入!"+i); }else{ System.out.println("不成功插入!"+i); } /*因为mybatis是轻量级的,默认是不提交事务的*/ session.commit(); System.out.println("已提交事务!"); } /*Update one*/ @Test public void updateUser(){ SqlSession session= factory.openSession(); User user = new User(); user.setId(4); user.setUsername("李军1"); user.setPassword("128"); user.setAge(21); user.setRemark("Asdsdsd"); int i=session.update("com.itcast.mapper.update", user); if(i==1){ System.out.println("成功更新!"+i); }else{ System.out.println("不成功更新!"+i); } /*因为mybatis是轻量级的,默认是不提交事务的*/ session.commit(); System.out.println("已提交事务!"); } /*delete one*/ @Test public void deleteOne(){ SqlSession session = factory.openSession(); int i =session.delete("com.itcast.mapper.deleteOne", 2); if(i==1){ System.out.println("成功删除!"+i); }else{ System.out.println("不成功删除!"+i); } /*因为mybatis是轻量级的,默认是不提交事务的*/ session.commit(); System.out.println("已提交事务!"); } /*delete many(for method)*/ @Test public void deleteMany(){ SqlSession session = factory.openSession(); int[] array1={5,6}; int i = session.delete("com.itcast.mapper.deleteMany", array1); /*因为mybatis是轻量级的,默认是不提交事务的*/ session.commit(); } /*get count*/ @Test public void getCount(){ SqlSession session = factory.openSession(); int i = session.selectOne("com.itcast.mapper.count"); System.out.println("记录条有:"+i); } } </span>
参数注意:parameterMap废除,它是ibatis的。后来给google了,改为使用parameterType
获取动态参数: ibatis: #name# ibatis mybatis: #{}, ${}
注意selectOne时,结果集必须是一条记录,否则mybatis报错
org.apache.ibatis.exceptions.TooManyResultsException:Expected one result (or null) to be returned by selectOne(), but found: 3
(6).当数据库表字段和实体对象属性名称不一致时,怎么处理?
解决办法:
1) 通过sql的字段命名别名,别名跟实体对象属性一致,它就将相应的结果封装到set方法中了
select id,user_name as name,age,remark fromperson
Mybatis它对象映射是通过结果集的字段名称,在映射文件最开始的时候,配置实体类和数据库表的关联了。
2) Mybatis最强大功能 resultMap对象(里面放实体类)
没写resultMap之前:
<span style="font-family:Microsoft YaHei;font-size:18px;"><?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.itcast.mapper"> <!-- 查询 注意MyBatis中如果有些集合类型,只填写元素的类型 --> <!-- 可以随意取 resultType="List<User>" mybatis可以去猜类型,所以我们不需要这样写,直接写类 --> <!-- 在这里和hibernate的映射文件就有很大的区别了 --> <!-- 执行结果,封装到对象结果集中,这个操作又底层操作完成 --> <select id="find" resultType="com.itcast.domain.User"> select * from user </select> <!-- 查询一个值 --> <select id="getid" parameterType="int" resultType="com.itcast.domain.User"> select * from user where id = #{pid} </select> </mapper> </span>
<span style="font-family:Microsoft YaHei;font-size:18px;"><?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.itcast.mapper"> <!-- 最强大的功能,resultMap 描述中间 对象属性和结果集中的对应关系 id取个名字--> <resultMap type="com.itcast.domain.User" id="UserRM"> <!-- 主键 property:实体属性 column:结果集的字段名(没写,默认就是数据库列名) --> <id property="id" column="id"/> <!-- 普通字段 --> <result property="username" column="username"/> <result property="password" column="password"/> <result property="age" column="age"/> <result property="remark" column="remark"/> <!-- 关联关系 --> </resultMap> <!-- 查询 注意MyBatis中如果有些集合类型,只填写元素的类型 --> <!-- 可以随意取 resultType="List<User>" mybatis可以去猜类型,所以我们不需要这样写,直接写类 --> <!-- 可以写resultMap 值为之前配置好的resultMap的id值 --> <!-- 在这里和hibernate的映射文件就有很大的区别了 --> <!-- 执行结果,封装到对象结果集中,这个操作又底层操作完成 --> <select id="find" resultMap="UserRM"> select * from user </select> <!-- 查询一个值 --> <select id="getid" parameterType="int" resultMap="UserRM"> select * from user where id = #{pid} </select> </mapper> </span>
(7).结果集
resultType 基础类型,int,string,Person
resultMap 针对resultMap标签(使用这个,一定要写resultMap配置)
(8).删除多个值
因为上面案例,我只写了整形数组删除多条,还有其他方法
Lsit方式删除
<span style="font-family:Microsoft YaHei;font-size:18px;"> <!-- 删除多条,LIST集合 --> <delete id="deleteList" parameterType="int"> delete from person where id in <foreach collection="list" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete> </span>
<span style="font-family:Microsoft YaHei;font-size:18px;">public void testDeleteByList(){ SqlSession session = factory.openSession(); List<Integer> _list = new ArrayList<Integer>(); _list.add(4); _list.add(6); session.delete("cn.itcast.mapper.PersonMapper.deleteList", _list); session.commit(); } </span>
<span style="font-family:Microsoft YaHei;font-size:18px;"><delete id="deleteMap" parameterType="int"> delete from person where id in <foreach collection="map" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete> </span>
<span style="font-family:Microsoft YaHei;font-size:18px;"><span style="font-family:Microsoft YaHei;"> @Test //删除多条 MAP public void testDeleteByMap(){ SqlSession session = factory.openSession(); Map<Integer,Object> paraMap = new HashMap<Integer,Object>(); paraMap.put("ids", 1); paraMap.put("ids", 2); session.delete("cn.itcast.mapper.PersonMapper.deleteMap", paraMap); session.commit(); } </span></span>
删除多条,Map , ids 代表map中key
<span style="font-family:Microsoft YaHei;font-size:18px;"><delete id="deleteMap" parameterType="map"> delete from person where id in <foreach collection="ids" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete> </span>
<span style="font-family:Microsoft YaHei;font-size:18px;">@Test //删除多条 MAP public void testDeleteByMap(){ SqlSession session = factory.openSession(); Map<String,Object> paraMap = new HashMap<String,Object>(); int[] ids = {4,6}; paraMap.put("ids", ids); session.delete("cn.itcast.mapper.PersonMapper.deleteMap", paraMap); session.commit(); } </span>
在配置文件sqlMapConfig.xml中增加别名
<span style="font-family:Microsoft YaHei;font-size:18px;"><!-- 起别名 --> <typeAliases> <typeAlias type="cn.itcast.domain.Person" alias="Person"/> </typeAliases> </span>
<span style="font-family:Microsoft YaHei;font-size:18px;"><!-- 查询一个,按id查询 --> <select id="get" parameterType="int" resultType="Person"> select * from person where id = #{pid} </select> </span>
(9).SQL片段
在映射文件中
<span style="font-family:Microsoft YaHei;font-size:18px;"><sql id="cols">id,user_name,age,remark</sql> <select id="find" resultMap="personRM"> select <include refid="cols"/> from person </select> </span>
传参:map和po对象实体,查询条件封装
例如:年龄(整数),出生日期,入职日期(日期)
日期,有开始时间,结束时间
Map随意构造
(10).动态SQL语句的使用
a)<where> 能自动去掉where最前面and或者or
<span style="font-family:Microsoft YaHei;font-size:18px;"> <select id="find" parameterType="map" resultMap="personRM"> select <include refid="cols"/> from person <where> <if test="name!=null">and user_name like #{name}</if> <if test="age!=null">and age=#{age}</if> </where> </select> </span>
(10).<set>自动删除最后一个逗号
<span style="font-family:Microsoft YaHei;font-size:18px;"><set> <if test="name!=null">user_name=#{name},</if> <if test="age!=null">age=#{age},</if> <if test="remark!=null">remark=#{remark},</if> </set> </span>
(11).遍历
<span style="font-family:Microsoft YaHei;font-size:18px;"> <foreach collection="ids" item="id" open="(" close=")" separator=","> #{id} </foreach> where id in ( <foreach collection="array" item="id" separator=","> #{id} </foreach> ) </span>
特殊字符处理 <![CDATA[ ]]> 转化成文本内容处理
<span style="font-family:Microsoft YaHei;font-size:18px;"><where> <if test="username!=null">username like #{username}</if> <if test="age!=null"><![CDATA[and age<=]]>#{age}</if> </where></span>
五、对象关联关系
1.一对一关联
说的首先得明白,hibernate中的一对的关联关系是在映射文件中注明的,在这点上和mybatis有很大的区别,mybatis中不需要这样注明两者之间的一对一关联,只需要是sql语句中,同时查询出来即可。
老规矩,首先MyBatis的配置文件sqlMapConfig.xml
<?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> <typeAlias type="com.itcast.domain.User" alias="Person"></typeAlias> <!-- <typeAlias type="" alias=""/> --> </typeAliases> <!-- 配置数据源,事务,当然最后整合的时候就交给spring了,default:采用哪种方式 --> <environments default="test"> <!-- id:test/deploy 一种是测试的时候用,另外一种是发布的时候用 --> <environment id="test"> <!-- 事务:JDBC/MANAGED-这是自己管理,后期就是给spring管理,这里使用JDBC管理 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据源:POOLED/UNPOOLED/JNDI --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisEg1?charsetEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> <environment id="deploy"> <!-- 事务:JDBC/MANAGED-这是自己管理,后期就是给spring管理,这里使用JDBC管理 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据源:POOLED/UNPOOLED/JNDI --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisEg1?charsetEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!-- 映射文件mapper 这里和hibernate一样的,本文件就和hibernate.cfg.xml一样功能,MyBatis引用了hibernate的一些思想--> <mappers> <mapper resource="com/itcast/mapper/UserMapper.xml"/> <mapper resource="com/itcast/mapper/UserInfMapper.xml"/> </mappers> </configuration>
信息自己添加,查询一下:
遇到这种id相同,到时候mybatis无法识别,然后存贮在实体类的时候,会出现问题,怎么处理?
很简单,在查询的时候,赋 别名
此一对一的例子,是在原来的基础上做的 UserMapper.xml文件依然不变。但是User实体类需要做点儿改变
定义
private User_inf user_inf;//一对一的体现,并且setget方法。
添加User_inf实体类:
package com.itcast.domain; import java.io.Serializable; import java.util.Date; public class User_inf implements Serializable{ private Integer id; private String inf; private Date time; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getInf() { return inf; } public void setInf(String inf) { this.inf = inf; } public Date getTime() { return time; } public void setTime(Date time) { this.time = time; } @Override public String toString() { return "User_inf [id=" + id + ", inf=" + inf + ", time=" + time + "]"; } }
配置resultMap第一种方式:(不常用,而且不好变通)
<!-- 最强大的功能,resultMap 描述中间 对象属性和结果集中的对应关系 id取个名字--> <resultMap type="com.itcast.domain.User" id="UserRM"> <!-- 主键 property:实体属性 column:结果集的字段名(没写,默认就是数据库列名) --> <id property="id" column="id"/> <!-- 普通字段 --> <result property="username" column="username"/> <result property="password" column="password"/> <result property="age" column="age"/> <result property="remark" column="remark"/> <!-- 关联关系 和hibernate的映射文件关联有很大的区别--> <!-- 一对一 javaType:只有在对一的时候采用--> <association property="user_inf" javaType="com.itcast.domain.User_inf"> <id property="id" column="id"/> <result property="inf" column="inf"/> <result property="time" column="time"/> </association> </resultMap>
配置resultMap第二种方式:(运用继承的方式常用,好变通)
<?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.itcast.mapper.userinfMapper"> <!-- 较UserMapper.xml文件的配置一样,一样是关联在一起的 不过更加灵活了,需要谁就使用谁--> <resultMap type="com.itcast.domain.User" id="userInfRm1"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="password" column="password"/> <result property="age" column="age"/> <result property="remark" column="remark"/> </resultMap> <!-- 一对一的那个,不想影响实体的话,就使用继承的方式: 对一使用 association 所对应使用的是javaType --> <resultMap type="com.itcast.domain.User" id="userInfRm2" extends="userInfRm1"> <association property="user_inf" javaType="com.itcast.domain.User_inf"> <id property="id" column="id"/> <result property="inf" column="inf"/> <result property="time" column="time"/> </association> </resultMap> <!-- 查询User及User_inf表中的一一对应关系 --> <select id="findUserAndInf" parameterType="map" resultMap="userInfRm2"> select p.id,p.username,p.password,p.age,p.remark, i.id as infid,i.inf,i.time from (select id,username,password,age,remark from user) p left join (select id,inf,time from user_inf) i on p.id=i.id <where> <if test="name!=null">username=#{name}</if> </where> </select> </mapper>
package com.itcast.test; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.itcast.domain.User; import com.itcast.util.MyBatisSqlSessionFactiorUtil; public class UserInfTest extends MyBatisSqlSessionFactiorUtil{ @Test public void test1(){ SqlSession session =factory.openSession(); Map map1 = new HashMap(); map1.put("name", "lijun"); List<User> list = session.selectList("com.itcast.mapper.userinfMapper.findUserAndInf", map1); for(User user:list){ System.out.println(user.toString()+"\n"+user.getUser_inf().toString()); } } }
错误:原因是因为,映射文件没有加入到配置文件中
2.一对多的关联
一对的对,记住一个就对多的概念,只需要负责对多的那边。hibernate中对多一半用set集合,而mybatis一般用list集合。
建一个Book表,表示一本书可以让多个人拥有。
修改User实体类:加对多 private List<Book> books;//一对多的体现 并且setget方法
添加Book实体类:
package com.itcast.domain; import java.io.Serializable; public class Book implements Serializable{ private Integer id; private String book_name; private Double book_money; //不配双向关联的 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getBook_name() { return book_name; } public void setBook_name(String book_name) { this.book_name = book_name; } public Double getBook_money() { return book_money; } public void setBook_money(Double book_money) { this.book_money = book_money; } @Override public String toString() { return "Book [id=" + id + ", book_name=" + book_name + ", book_money=" + book_money + "]"; } }
<?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.itcast.mapper.userinfMapper"> <!-- 较UserMapper.xml文件的配置一样,一样是关联在一起的 不过更加灵活了,需要谁就使用谁--> <resultMap type="com.itcast.domain.User" id="userInfRm1"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="password" column="password"/> <result property="age" column="age"/> <result property="remark" column="remark"/> </resultMap> <!-- 一对一的那个,不想影响实体的话,就使用继承的方式: 对一使用 association 所对应使用的是javaType --> <resultMap type="com.itcast.domain.User" id="userInfRm2" extends="userInfRm1"> <association property="user_inf" javaType="com.itcast.domain.User_inf"> <id property="id" column="id"/> <result property="inf" column="inf"/> <result property="time" column="time"/> </association> </resultMap> <!-- 一对多的那个,不想影响实体的话,就使用继承的方式 : 对多使用:collection,所对应使用的是ofType(一完之前涉及到一对一,如果需求里面只要一对多,就继承主的那个,如果两个都需要,就继承第二个)--> <resultMap type="com.itcast.domain.User" id="userBookRm" extends="userInfRm2"> <collection property="books" ofType="com.itcast.domain.Book"> <id property="id" column="id"/> <result property="book_name" column="book_name"/> <result property="book_money" column="book_money"/> </collection> </resultMap> <!-- 查询User及User_inf表中的一一对应关系 --> <select id="findUserAndInf" parameterType="map" resultMap="userInfRm2"> select p.id,p.username,p.password,p.age,p.remark, i.id as infid,i.inf,i.time from (select id,username,password,age,remark from user) p left join (select id,inf,time from user_inf) i on p.id=i.id <where> <if test="name!=null">username=#{name}</if> </where> </select> <!-- 查询User及User_inf表中的一一对应关系及User到book的一对多:有条件的一条数据 --> <select id="Book" parameterType="map" resultMap="userBookRm"> select p.id,p.username,p.password,p.age,p.remark,p.infid,p.inf,p.time,b.bookid,b.book_name,b.book_money from ( select p.id,p.username,p.password,p.age,p.remark,i.infid,i.inf,i.time from (select id,username,password,age,remark from user) p left join (select id as infid,inf,time from user_inf) i on p.id=i.infid )p left join(select id as bookid,book_name,book_money,userid from book) b on p.id=b.userid <where> <if test="name!=null">username=#{name}</if> </where> </select> </mapper>
测试类:UserBookTest.java
package com.itcast.test; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.itcast.domain.User; import com.itcast.util.MyBatisSqlSessionFactiorUtil; public class UserBookTest extends MyBatisSqlSessionFactiorUtil{ @Test public void bookTest(){ SqlSession session = factory.openSession(); Map map1 = new HashMap(); map1.put("name", "lijun"); List<User> users = session.selectList("com.itcast.mapper.userinfMapper.Book",map1); for(User user:users){ System.out.println("User信息:"+user.toString()+"\n Inf信息:"+user.getUser_inf().toString()+"\n Book信息:"+user.getBooks().toString()); } System.out.println(users.size()); } }
六、SQL优化的问题
前面说过hibernate的JDBC底层封装,就注定了无法优化HQL语句的性能,但是MyBatis的sql语句是轻量级的封装,依然保持着写SQL语句的习惯,这就意味着想优化系统的性能,可以在Sql语句上去优化。
七、视图的问题
在做大型项目,视图可能废除。项目组不允许在项目中使用视图
八、总结
还没完呢?继续下一篇文章