问题?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>
记得要创建数据库,我新建的是MyBatisEg1,暂时不需要建表,先测试搭建成功没
(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>
因为SqlSessionFactory它是一个线程安全,SqlSession它是线程不安全。sqlSessionFactory在这里我们就可以抽取成工具类了。(工具类很好理解,就是在线程上保证安全,也是公共要使用的,抽出来共同使用即可)
参数注意: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>
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">
<!-- 最强大的功能,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>
test
<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>
Map方式删除
<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>
test
<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>
test
<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>
(8).实体类别名
在配置文件sqlMapConfig.xml中增加别名
<span style="font-family:Microsoft YaHei;font-size:18px;"><!-- 起别名 -->
<typeAliases>
<typeAlias type="cn.itcast.domain.Person" alias="Person"/>
</typeAliases>
</span>
在UserMapper.xml(映射文件)中使用
<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>
(12).特殊符号的处理
特殊字符处理 <![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>
扩展拓展用户信息职业,新建另外一个对一的表:user_inf(id和user中的id对应)
信息自己添加,查询一下:
遇到这种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 + "]";
}
}
添加映射配置文件UserInfMapper.xml
配置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>
建立测试类:UserInfTest
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 + "]";
}
}
映射文件直接可以在 UserInfMapper.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.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>
在这个映射文件中可以看出采用继承的方式的好处,到时候可以想用那个就可以用那个 resultMap,很方便,比上面一种直接全部属性卸载一个 resultMap变通很多。
测试类: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语句上去优化。
七、视图的问题
在做大型项目,视图可能废除。项目组不允许在项目中使用视图
八、总结
还没完呢?继续下一篇文章看看MyBatis的插件自动生成实体类和映射文件的方法吧查看博客文章