今天得知马上要考核了,心里还是有那么紧张的,虽然紧张,也不能阻止我总结今天学习的东西。。。。嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻
下面直接说今天学习的内容。
一.jar包
要想使用Mybatis开源框架来作为持久层,那么导入Mybatis的相关jar包是必不可少的。
二.创建Mybatis的核心配置文件
和hibernate,spring一样,Mybatis也有自己的核心配置文件,这个文件的文件名和位置不是固定的。但我们通常把它放在src目录下。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入Mybatis的约束,在编写代码的时候会有提示 -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 编写配置 -->
<configuration>
<!-- 利用log4j记录执行的sql语句 -->
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="logImpl" value="LOG4J" />
</settings>
<!-- 为类配置别名,防止代码繁重 .
一个类型好像可以同时有好几个别名,即使没有typeAliases标签,
mapper.xml也能找到 默认的类别名(可以认为configuration标签中默认有一个typeAliases标签
用来存放系统提供的默认类别名(zijilijie))。
-->
<typeAliases>
<typeAlias alias="User" type="com.java.Bean.User"/>
<typeAlias alias="zidingyi_map" type="java.util.Map"/>
<typeAlias alias="string" type="java.lang.String"/>
</typeAliases>
<environments default="development">
<environment id="development">
<!-- 先定义事务管理器,管理的底层表现为JDBC -->
<transactionManager type="JDBC"/>
<!-- 数据源类型定义为 池类型 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssgl"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<!-- 引入mapper.xml 使在查询的时候,可以对应上相应的接口-->
<mappers>
<mapper resource="com/java/Dao/UserMapper.xml"></mapper>
<mapper resource="com/java/Dao/DormitoryMapper.xml"></mapper>
</mappers>
</configuration>
这是mybatis最基本的核心配置文件,它定义了事务管理器和数据源,并且也导入了相关的mapper映射文件。在该文件的上方,利用log4j来记录执行的sql语句,在它的下面配置了类的别名。为类配置别名,防止代码繁重 ,一个类型可以同时有好几个别名,即使没有typeAliases标签,mapper.xml也能找到 默认的类别名(可以认为configuration标签中默认有一个typeAliases标签
用来存放系统提供的默认类别名(自己理解))。
三.创建相应的接口和对应的mapper映射文件
我们需要定义一个接口,用于存放操作数据库的方法,并在映射文件中将这个接口实现。
package com.java.Mapper;
import java.util.List;
import java.util.Map;
import com.java.Bean.User;
//创建接口,用于映射mapper.xml,并且定义所要操作数据库的方法
public interface UserMapper {
//定义要操作数据库的方法
public User select_one_user(User user);
public User select_one_user1(User user);
public List<User> select_map_user(User user);
}
映射文件:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入所需要的约束,用来约定在该xml文件中能够使用的标签,并在写标签的时候有提示功能 -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 进行配置 映射文件,将接口中的方法一一实现 -->
<mapper namespace="com.java.Mapper.UserMapper">
<!-- 简化sql代码 -->
<sql id="select_1">
select * from t_user
</sql>
<!-- 定义结果集 -->
<resultMap id="user_map" type="User">
<result column="userid" property="userId" javaType="string"></result>
<result column="userpassword" property="userPassword" javaType="string"></result>
<result column="username" property="userName" javaType="string"></result>
<result column="usersex" property="userSex" javaType="string"></result>
<result column="userrole" property="userRole" javaType="string"></result>
<result column="usercollege" property="userCollege" javaType="string"></result>
<result column="usermajor" property="userMajor" javaType="string"></result>
<result column="userclass" property="userClass" javaType="string"></result>
<result column="dormitoryid" property="dormitoryId" javaType="string"></result>
</resultMap>
<select id="select_one_user" parameterType="com.java.Bean.User" resultType="com.java.Bean.User">
select * from t_user where userId= #{userId}
</select>
<select id="select_one_user1" parameterType="User" resultType="User">
select * from t_user where userId= #{userId}
</select>
<!-- 演示查询结果集的情况 ,只定义实现,没有接口,不会报错-->
<select id="select_map_user" parameterType="User" resultMap="user_map">
<include refid="select_1"></include>
where username= #{userName}
</select>
</mapper>
当我们在测试类的时候,需要定义所要所要执行的方法类型,比如在《select》标签内,进行查询操作。注意,标签的id值要和 要映射的接口的类路径相同,这也是方便虚拟机进行映射。parameterTyep 的值是接口方法的参数类型,resultType 的值是查询语句查询出来的每一行的类型。resultMap类型就是自定义的类型,通常用于进行表联查,resultMap 的type值同样的是查询语句从数据库中查询出来的每一行的类型,也就是resultMap 的type类型值可以封装查询出来的每一行即可。
上述代码还有简化sql的代码,也就是将重复的sql语句进行的封装,然后在所需要的时候进行引入。
四.进行测试
下面贴一下测试的代码:
package com.java.Text;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
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 com.java.Mapper.DormitoryMapper;
public class Text2 {
public static void main(String[] args) throws IOException {
//指定Mybatis核心配置文件的路径
String url="Mybatis.xml";
//用流对象读取(加载)核心配置文件
InputStream inputStream=Resources.getResourceAsStream(url);
//创建一个SqlSessionFactory工厂用于指向这个文件(指向数据库)
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//获得sessoin用于操作数据库
SqlSession sqlSession=sqlSessionFactory.openSession();
//将session绑定操作数据库的方法,得到操作数据库的对象
DormitoryMapper dormitoryMapper=sqlSession.getMapper(DormitoryMapper.class);
//调用方法
//Map集合是无序的,直接输出map,是可以得到结果的
Map map=dormitoryMapper.select_one_dormitory("1");
System.out.println(map);
//遍历map
for(Object key:map.keySet()) {
System.out.print(map.get(key)+"-----");
}
//按照非主键来进行查询
List<Map> list=dormitoryMapper.select_dormitory_byPlay(1);
//进行遍历
System.out.println(list);
for(Map map2:list) {
System.out.println(map2);
}
/*验证由于返回值类型不一致,而导致的返回值为空的情况
*
*接口中的返回值类型要和mapper.xml文件中的返回值类型一样,要不查询到的返回值将不能接收到。
*
*/
List<Map> map_error=dormitoryMapper.select_dormitory_byPlay2(1);
System.out.println(map_error);
}
}
其实,mapper方法的返回值类型是什么就返回什么类型,只要接口中的方法返回值可以接收mapper返回的值就可以。但是一旦接口中的方法返回值类型接收不了mapper方法的返回值(可能由于类型不一样),那么就会抛出异常。
五.三表联查
在进行几个表同时联合查询的时候,那么这几个表必然会通过主键和外键联系在一起。这时候就需要把这几个表中相同的字段删除掉(其实不删的话我猜也可以,明天我验证一下,然后在明天的博客我会 说一下demo的结果)。删除掉相应外键,并定义一个外键联系的表的对应的实体类类型字段(属性),用于封装查询到的对象。在一对多的里面,会定义一个集合用来承载查询到的多的一方,在多对一的类里面,会定义一个多的一方的类的对象属性,用来承载一的一方。
下面是多表联查的mapper映射文件代码。
<?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.zf.dao.UserMapper">
<!-- 自定义resultMap -->
<resultMap type="User" id="my_map_1">
<result column="userid" property="userId"/>
<result column="userpwd" property="userPwd"/>
<result column="username" property="userName"/>
<result column="usersex" property="userSex"/>
<result column="userrole" property="userRole"/>
<result column="usercollege" property="userCollege"/>
<result column="usermajor" property="userMajor"/>
<result column="userclass" property="userClass"/>
<!-- 站在多方配置一方信息使用association -->
<association property="dormitory" javaType="com.zf.bean.Dormitory">
<result column="dormitoryid" property="dormitoryId"/>
<result column="planpersons" property="planPersons"/>
<result column="realpersons" property="realPersons"/>
<result column="waterprice" property="waterPrice"/>
<result column="powerprice" property="powerPrice"/>
<result column="grade" property="grade"/>
</association>
<!-- 站在一方角度配置多方信息 -->
<collection property="lates" ofType="com.zf.bean.Late">
<result column="lateid" property="lateId"/>
<result column="latetime" property="lateTime"/>
</collection>
</resultMap>
<!-- 查询语句 -->
<select id="sel_user_dor_late" parameterType="User" resultMap="my_map_1" >
select * from t_user u join t_dormitory d
on u.dormitoryid = d.dormitoryid
join t_late l
on u.userid = l.userid
where u.userid = #{userId}
</select>
</mapper>
六.Mabatis中#{}和${}的区别
动态 sql 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析(也就是将传进来的参数和事先定义好的sql语句组成一个可以在数据库中执行的sql文)。mybatis 为我们提供了两种支持动态 sql 的语法:#{} 以及 ${}。
在下面的语句中,如果 username 的值为 zhangsan,则两种方式无任何区别:
但是 #{} 和 ${} 在预编译中的处理是不一样的。#{} 在预处理时,会把参数部分用一个占位符 ? 代替,变成如下的 sql 语句:
而 ${} 则只是简单的字符串替换,在动态解析阶段,该 sql 语句会被解析成:
以上,#{} 的参数替换是发生在 DBMS 中,而 ${} 则发生在动态解析过程中。
那么,在使用过程中我们应该使用哪种方式呢?
答案是,优先使用 #{}。因为 ${} 会导致 sql 注入的问题。看下面的例子:
在这个例子中,如果表名为
user; delete user; --
则动态解析之后 sql 如下:
--之后的语句被注释掉,而原本查询用户的语句变成了查询所有用户信息+删除用户表的语句,会对数据库造成重大损伤,极大可能导致服务器宕机。
但是表名用参数传递进来的时候,只能使用 ${} ,具体原因可以自己做个猜测,去验证。这也提醒我们在这种用法中要小心sql注入的问题。