【SSM】 MyBatis 笔记


一、MyBatis使用步骤:

① 导入 mybatis.jar ,mysql-connector-java.jar 等jar包
conf.xml (数据库配置信息、映射文件)
③ 数据库表-实体类:映射文件 mapper.xml
④ 测试


二、基础方式的增删改查:

mybatis约定:
输入参数 parameterType 和 输出参数 resultType ,在形式上都只能有一个

1 输入参数 :

① 如果是简单类型(8个基本类型+String) 可以使用占位符#{xxxx}
② 如果是对象类型,则必须是对象的属性 #{属性名}

2 输出参数:

如果返回值类型是一个 对象(如Student),则无论返回一个、还是多个resultType 都写成 xxx.xxxx.entity.Student
resultType="xxx.xxx.entity.Student"

3 注意事项:

① 如果使用的 事务方式为 jdbc,则需要 commit提交,即session.commit();
② 所有的标签如 < select > < update >等 ,都必须有sql语句,但是sql参数值可选

例如:select * from student  where sno= #{sno}

sql 有参数:session.insert(statement, 参数值 );
sql 没参数:session.insert(statement);


三、mapper动态代理方式的crud (MyBatis接口开发):

原则:约定优于配置

1 硬编码方式

xxx.java
	Configuration conf = new Configuration();
	con.setName("myProject") ;

2 配置方式:

xxx.xml   
	<name>myProject</name>

约定:默认值就是myProject

3 具体实现的步骤:

(1)基础环境

mybatis.jarmysql-connector-java.jarconf.xmlmapper.xml


(2)不同之处

约定的目标省略掉statement , 即 根据约定 直接可以定位出SQL语句


(3)接口

接口中的方法必须遵循以下约定
方法名mapper.xml文件中标签的id值相同

② 方法的 输入参数mapper.xml文件中标签的 parameterType类型一致 (如果mapper.xml的标签中没有 parameterType,则说明方法没有输入参数)

③ 方法的返回值mapper.xml文件中标签的 resultType类型一致 (无论查询结果是一个 还是多个(student、List),在mapper.xml标签中的resultType只写 一个(Student);

如果没有resultType,则说明方法的返回值void

除了以上约定,要实现 接口中的方法mapper.xml 中SQL标签一一对应,还需要注意:namespace的值 ,就是 接口的全类名( 接口 - mapper.xml 一一对应)

例:

在mapper.xml 中namespace设置如下,PersonMapper为接口的全类名

<mapper namespace="org.lanqiao.mapper.PersonMapper"> 

4 匹配的过程:(约定的过程)

1)根据 接口名 找到 mapper.xml文件
根据的是namespace=接口的全类名

2)根据 接口的方法名 找到 mapper.xml文件的SQL标签
方法名=SQL标签的Id值

以上2点可以保证: 当我们调用接口中的方法时,
程序能自动定位到 某一个mapper.xml文件中的sql标签

ps:SQL映射文件(mapper.xml) 和 接口放在同一个包中 (注意修改conf.xml中加载mapper.xml文件的路径)

以上,可以通过 接口的方法->SQL语句

执行语句:

PersonMapper personMapper = session.getMapper(PersonMapper.class) ;
personMapper.方法();

例:

//通过id查询信息
	public static void queryPersonById(int id) throws IOException
	{
		// 加载MyBatis配置文件(为了访问数据库)
		Reader reader = Resources.getResourceAsReader("conf.xml");
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
		SqlSession session = sessionFactory.openSession();
		
		PersonMapper personMapper = session.getMapper(PersonMapper.class);
		
		Person person = personMapper.queryPersonById(id);
		
		System.out.println(person.toString());
		session.close();
	}

通过session对象获取接口(session.getMapper(接口.class);),再调用该接口中的方法,程序会自动执行该方法对应的SQL语句


5 优化

(1)将配置信息单独放入 db.properties文件中,然后再动态引入db.properties:

① File文件db.properties的内容

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/xxx
username=root
password=123456

② conf.xml 中 添加

<configuration>
<properties  resource="db.properties"/>

③ 引入之后,使用${key}

<dataSource type="POOLED">
	<!-- 配置数据库信息 -->
	<property name="driver" value="${driver}"/>
	<property name="url" value="${url}" />
	<property name="username" value="${username}" />
	<property name="password" value="${password}"/>
</dataSource>

(2)MyBatis全局参数在conf.xml中设置 ,设置方式如下

<settings>
		<setting name="cacheEnabled" value="true"  />
		<setting name="lazyLoadingEnabled" value="true"  />
</settings>

(3).别名 conf.xml
设置单个别名批量设置别名

<typeAliases>
	<!-- 单个别名 (别名 忽略大小写) -->
	<typeAlias type="org.lanqiao.entity.Student" alias="student"/> 
	<!--  批量定义别名  (别名 忽略大小写),以下会自动将该包中的所有类 批量定义别名: 别名就是类名(不带包名,忽略大小写)   -->
	<package name="org.lanqiao.entity"/>
</typeAliases>

四、输入参数:parameterType详解

1 类型为 简单数据类型(8个基本类型+String)

(1)#{}、${}的区别

① 区别一:

#{任意值}
${value} ,其中的标识符只能是value

② 区别二:

#{}自动给String类型加上’ ’ (自动类型转换)
${} 原样输出,但是适合于 动态排序(动态字段)

select *  from student where stuname = #{value}

select *  from student where stuname = '${value}'
//动态排序:
select *  from student order by ${value} asc

③ 区别三:

#{}可以防止SQL注入
${}不防止


(2)${}、#{}相同之处:

都可以 获取对象的值 (嵌套类型对象)

模糊查询,方式一:

select stuno,stuname,stuage  from student where stuage= #{stuAge}  or stuname like #{stuName} 
Student student = new Student();
student.setStuAge(24);
student.setStuName("%w%");
List<Student> students = studentMapper.queryStudentBystuageOrstuName(student) ;//接口的方法->SQL

模糊查询,方式二:

student.setStuName("w");
	select stuno,stuname,stuage  from student where stuage= #{stuAge}  or stuname like '%${stuName}%'

嵌套类型对象

2.对象类型
#{属性名}
${属性名}


五、输出参数:resultType详解

(1) 简单类型( 8个基本数据类型+String

(2) 输出参数为 实体对象类型

(3) 输出参数为 实体对象类型的集合 :虽然输出类型为集合,但是resultType依然写 集合的元素类型(resyltType=“Student”)

(4) 输出参数类型为 HashMap
HashMap本身是一个集合,可以存放多个元素,但是返回值为HashMap时 ,查询的结果只能是1个学生的多个属性

结论:一个HashMap 对应一个学生的多个属性 【一个map,一个学生】

例:二维数组
{
     {1,zs,23,xa}, -一个HashMap对象
     {2,ls,24,bj},
     {3,ww,25,tj}
}

注意:当属性名字段名 不一致时,除了使用resultMap以外,还可以使用resultType+HashMap:

(1)resultMap

<resultMap type="student" id="queryStudentByIdMap">
			<!-- 指定类中的属性 和 表中的字段 对应关系 -->
			<id property="stuNo"  column="id" />
			<result property="stuName" column="name" />
	</resultMap>

(2) resultType+HashMap

select 表的字段名 “类的属性名” from… 来制定字段名 和属性名的对应关系

<select id="queryStudentByIdWithHashMap" 	 parameterType="int"	resultType="student" >
	select id "stuNo",name "stuName" from student where id = #{id}
</select>

注意: 如果发现某一个字段结果始终为默认值(0,0.0,null),则可能是 表的字段类的属性名字写错。


六、动态SQL:

where

<select id="queryStuByNOrAWishSQLTag" 	 parameterType="student"	resultType="student" >
	select stuno,stuname,stuage from student
	<where>
		<!-- <if test="student有stuname属性 且不为null"> -->
		<if test="stuName !=null and stuName!=''  "> 
			and stuname = #{stuName}
		</if>
		<if test="stuAge !=null and stuAge!=0  "> 
			 and stuage = #{stuAge}
		</if>
	</where>
</select>

注意:< where > 会自动处理第一个< if >标签中的 and,但不会处理之后中的and


foreach

迭代的类型:数组、对象数组、集合、属性(Grade类: List ids)

属性(Grade类: List ids)

简单类型的数组:
无论编写代码时,传递的是什么参数名(stuNos),在mapper.xml中 必须用 array 代替该数组

集合:
无论编写代码时,传递的是什么参数名(stuNos),在mapper.xml中 必须用 list 代替该数组

对象数组:
Student[] students = {student0,student1,student2} 每个studentx包含一个学号属性

注意:

parameterType="Object[]" 
	 	<foreach collection="array" open=" and  stuno in (" close=")" 
	  		 		item="student" separator=",">   
	  		 		#{student.stuNo}
	  	</foreach>
<!-- 将多个元素值 放入对象的属性中 -->
<select id="queryStudentsWithNosInGrade"  parameterType="grade" resultType="student">
  	select * from student 
  	<where>
  		 <if test="stuNos!=null and stuNos.size>0">
  		 	<foreach collection="stuNos" open=" and  stuno in (" close=")" 
  		 		item="stuNo" separator=",">   
  		 		#{stuNo}
  		 	</foreach>
  		 </if>
  	</where>
</select>
<!-- 将多个元素值 放入数组中 int[] stuNos = {1,2,53} -->
	<select id="queryStudentsWithArray"  parameterType="int[]" resultType="student">
	  	select * from student 
	  	<where>
	  		 <if test="array!=null and array.length">
	  		 	<foreach collection="array" open=" and  stuno in (" close=")" 
	  		 		item="stuNo" separator=",">   
	  		 		#{stuNo}
	  		 	</foreach>
	  		 </if>
	  	</where>
	</select>

七、关联查询:

(1)一对一 (association):

① 业务扩展类 (不常用)
核心:用resultType指定类的属性 包含多表查询的所有字段

② resultMap
通过 属性成员 将2个类建立起联系

<resultMap type="student" id="student_card_map">
		<!-- 学生的信息 -->
		<id  property="stuNo" column="stuNo"/>
		<result property="stuName" column="stuName" />
		<result property="stuAge" column="stuAge" />
		<!-- 一对一时,对象成员使用 association映射;javaType指定该属性的类型-->
		<association property="card" javaType="StudentCard" >
				<id property="cardId" column="cardId"/>
				<result property="cardInfo" column="cardInfo"/>
		</association>
</resultMap>
(2)一对多 (collection):

表:student studentclass (关联:classid)
类:student studentClass (关联:List students )

select  c.*,s.* from student s
		inner join studentclass c 
		on c.classid = s.classid
		where c.classid = 1;

【 MyBatis:多对一,多对多的本质就是 一对多的变化 】


八、日志:Log4j

① Log4j: log4j.jar (mybatis.zip中lib中包含此jar)
② 开启日志,conf.xml

<settings>
	<!-- 开启日志,并指定使用的具体日志 -->
	<setting name="logImpl" value="LOG4J"/>
</settings>

如果不指定,Mybatis就会根据以下顺序 寻找日志

SLF4J →Apache Commons Logging →Log4j 2 → Log4j →JDK logging

③ 编写配置日志输出文件

log4j.properties,内容
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

日志级别:DEBUG<INFO<WARN<ERROR

如果设置为info,则只显示 info及以上级别的信息;

建议:在开发时设置debug,在运行时设置为info或以上。】

可以通过日志信息,详细的阅读mybatis执行情况( 观察mybatis实际执行sql语句 以及SQL中的参数返回结果


九、延迟加载(懒加载):

( 一对一、一对多、多对一、多对多 )

一对多:班级-学生 ,
如果不采用延迟加载 (立即加载),查询时会将 一 和多 都查询,班级、班级中的所有学生。
如果想要 暂时只查询1的一方, 而多的一方 先不查询 而是在需要的时候再去查询 -->延迟加载

一对一:学生、学生证

mybatis中使用延迟加载,需要先配置:

<settings>
	<!-- 开启延迟加载 -->
	<setting name="lazyLoadingEnabled" value="true"/>
	<!-- 关闭立即加载 -->
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>

【 如果增加了mapper.xml ,要修改conf.xml配置文件(将新增的mapper.xml加载进去) 】

通过debug可以发现, 如果程序只需要学生,则只向数据库发送了查询学生的SQL;当我们后续 需要用到学生证的时候,再第二次发送 查询学生证的SQL。

一对多:和一对一的延迟加载配置方法相同

延迟加载的步骤:先查班级,按需查询学生
① 开启延迟加载conf.xml配置settings
② 配置mapper.xml
( 写2个Mapper: )
班级mapper.xml

<select id="queryClassAndStudents"   resultMap="class_student_lazyLoad_map">
	select  c.* from studentclass c
</select>		

<resultMap type="studentClass" id="class_student_lazyLoad_map">
	<!-- 因为 type的主类是班级,因此先配置班级的信息-->
	<id  property="classId" column="classId"/>
	<result  property="className" column="className"/>
	<!-- 配置成员属性学生,一对多;属性类型:javaType,属性的元素类型ofType -->
	<!-- 2222222再查班级对应的学生 -->
	<collection property="students" ofType="student" select="org.lanqiao.mapper.StudentMapper.queryStudentsByClassId" column="classid">

	</collection>
</resultMap>

	即查询 学生的sql是通过 select属性指定,并且通过column指定外键

学生mapper.xml

<!-- 一对多,延迟加载需要的: 查询班级中的所有学生 -->
<select id="queryStudentsByClassId" parameterType="int" resultType="student">
	select * from student where classId = #{classId}
</select>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值