MyBatis配置文件编写及CRUD操作
实验要求:
掌握MyBatis的配置文件的编写与使用。
实验内容:
实验1:参考教材2.1、2.2和2.3小节的内容,配置文件中<properties>、<typeAliases>、<environments>以及<mappers>元素的使用,完成SqlSession工具类的编写。总结核心配置文件及映射文件各种属性的使用方法。
实验2:完成教材案例2.4,员工管理系统的员工信息的CRUD。
实验3:完成教材案例3.5,学生信息查询功能。
实验4:(选)利用Mybatis完成银行转账系统的DAO层的功能改造
实验分析:
- 实验1主要是掌握配置文件中<properties>、<typeAliases>、<environments>以及<mappers>元素的使用。总结核心配置文件及映射文件各种属性的使用方法。
- 实验2员工管理系统
- 实验3学生信息查询系统
- 实验4参考JDBC版的银行转账系统
实验操作所用工具(软件):
IntelliJ IDEA 2021.2.1
实验1
一、Mybatis的全局配置文件
properties
将数据库连接参数单独配置在db.properties(名称可变)中,放在类路径下。这样只需要在SqlMapConfig.xml中加载db.properties的属性值。这样在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其它xml可以引用该db.properties
typeAliases
typeAliases可以用来自定义别名。在mapper.xml中,定义很多的statement,而statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
environments
MyBatis 可以配置多种环境。这会帮助你将 SQL 映射应用于多种数据库之中。但是要记得一个很重要的问题:你可以配置多种环境,但每个数据库对应一个 SqlSessionFactory。所以,如果你想连接两个数据库,你需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,你就需要三个实例,以此类推。
mappers
Mapper配置的几种方法:
第一种(常用)
<mapper resource=" " /> resource指向的是相对于类路径下的目录
如:<mapper resource="xxx/User.xml" />
第二种
<mapper url=" " /> 使用完全限定路径
如:<mapper url="file:///D:\xxxxx\xxx\User.xml" />
第三种
<mapper class=" " /> 使用mapper接口类路径
如:<mapper class="cn.xx.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
第四种(推荐)
<package name=""/> 注册指定包下的所有mapper接口
如:<package name="cn.xx.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
使用示例:
<mappers>
<mapper resource="xxx/User.xml"/>
<package name="cn.xx.mapper"/>
</mappers>
二、Mapper映射文件
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心
Mapper映射文件是一个xml格式文件,必须遵循相应的dtd文件规范,如ibatis-3-mapper.dtd
Mapper映射文件是以作为根节点,在根节点中支持9个元素,分别为insert、update、delete、select(增删改查);cache、cache-ref、resultMap、parameterMap、sql。
(一)select、parameterMap、resultType、resultMap
1、<select
<!-- (1)id (必须配置)
id是命名空间中的唯一标识符,可被用来代表这条语句。
一个命名空间(namespace) 对应一个dao接口,
这个id也应该对应dao里面的某个方法(相当于方法的实现),因此id 应该与方法名一致
-->
id="findUserById" --- 对应接口中的方法名
<!--(2)parameterType (可选配置, 默认为mybatis自动选择处理)
将要传入语句的参数的完全限定类名或别名, 如果不配置,mybatis会通过ParameterHandler 根据参数类型默认选择合适的typeHandler进行处理
parameterType 主要指定参数类型,可以是int, short, long, string等类型,也可以是复杂类型(如对象)
-->
parameterType="int"
<!-- (3)resultType (resultType 与 resultMap 二选一配置)
resultType用以指定返回类型,指定的类型可以是基本类型,可以是java容器,也可以是javabean
-->
resultType="User"
<!--(4)resultMap (resultType 与 resultMap 二选一配置)
resultMap用于引用我们通过 resultMap标签定义的映射类型,这也是mybatis组件高级复杂映射的关键
-->
resultMap="userResultMap"
<!--(5)flushCache (可选配置)
将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false
-->
flushCache="false"
<!--(6)useCache (可选配置)
将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true
-->
useCache="true"
<!--(7)timeout (可选配置)
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)
-->
timeout="10000"
<!-- (8)fetchSize (可选配置)
这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动)
-->
fetchSize="256"
<!--(9)statementType (可选配置)
STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED
-->
statementType="PREPARED"
<!--(10)resultSetType (可选配置)
FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一个,默认值为 unset (依赖驱动)
-->
resultSetType="FORWARD_ONLY"
>
2、parameterType(输入类型)
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。
#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?。
例如:
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
- 使用占位符#{}可以有效防止sql注入,在使用时不需要关心参数值的类型,mybatis会自动进行java类型和jdbc类型的转换。
- #{}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}和#{}的区别
- ${}和#{}不同,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换,可 以 接 收 简 单类 型 值 或 pojo属 性 值 , 如 果 parameterType 传 输 单 个 简 单 类 型 值 ,{}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}括号中只能是value。使用不能防止sql注入 ,但 是 有 时 用 {}不能防止sql注入,但是有时用不能防止sql注入,但是有时用{}会非常方便,如下的例子:
<select id="selectUserByName" parameterType="string" resultType="user">
select * from user where username like '%${value}%'
</select>
使用#{}则传入的字符串中必须有%号,而%是人为拼接在参数中,显然有点麻烦,如果采用在 s q l 中 拼 接 为 传 递 参 数 就 方 便 很 多 。 如 果 使 用 {}在sql中拼接为%的方式则在调用mapper接口 传递参数就方便很多。如果使用在sql中拼接为传递参数就方便很多。如果使用{}原始符号则必须人为在传参数中加%。
使用#的如下:
List<User> list = userMapper.selectUserByName("%管理员%");
3、resultType(返回值类型)
- 使用resultType可以进行输出映射,只有查询出来的列名和pojo中的属性名一致,才可以映射成功。如果查询出来的列名和pojo中的属性名全部不一致,就不会创建pojo对象。但是只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
- resultType可以输出简单类型。例如查询用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页。
<!-- 获取用户列表总数 -->
<select id="findUserCount" parameterType="user" resultType="int">
select count(*) from user
</select>
resultType可以输出pojo对象和pojo列表。当使用动态代理时,输出pojo对象和输出pojo列表在xml映射文件中定义的resultType是一样的,而生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList (返回集合对象调用 )。
4、resultMap(输出结果映射)
mybatis中可以使用resultMap完成高级输出结果映射。如果查询出来的列名和定义的pojo属性名不一致,就可以通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。然后使用resultMap作为statement的输出映射类型。resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
实验2
实验3
实验4
Resource
db.properties(数据库连接配置文件)
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&\ characterEncoding=utf8&useUnicode=true&useSSL=false
username=root
password=1
mybatis-config.xml(MyBatis的核心配置文件)
<?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>
<!-- 环境配置 -->
<!-- 加载类路径下的属性文件 -->
<properties resource="db.properties"> </properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 数据库连接相关配置,db.properties文件中的内容 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/AccountMapper.xml"/>
<mapper resource="mapper/LogMapper.xml"/>
</mappers>
</configuration>
AccountMapper.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.cqust.pojo.Account">
<insert id="addAccount" parameterType="com.cqust.pojo.Account">
insert into tb_account (username,cardID,balance) values (#{username},#{cardID},#{balance})
</insert>
<update id="deposit" parameterType="com.cqust.pojo.Account">
update tb_account set balance = balance + #{balance} where cardID=#{cardID}
</update>
<update id="withdrawal" parameterType="com.cqust.pojo.Account">
update tb_account set balance = balance - #{balance} where cardID=#{cardID}
</update>
<update id="transfer" parameterType="com.cqust.pojo.Account">
update tb_account set balance = balance - #{balance} where cardID=#{cardID}
</update>
</mapper>
LogMapper.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.cqust.pojo.Log">
<insert id="addLog" parameterType="com.cqust.pojo.Log">
insert into tb_log (name,type,amount,time) values (#{name},#{type},#{amount},#{time})
</insert>
<insert id="transferLog" parameterType="com.cqust.pojo.Log">
insert into tb_log (name,type,amount,outUser,inUser,time) values (#{name},#{type},#{amount},#{outUser},#{inUser},#{time})
</insert>
</mapper>
pojo层
Account类
package com.cqust.pojo;
public class Account {
private int id;
private String username;
private String cardID;
private double balance;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCardID() {
return cardID;
}
public void setCardID(String cardID) {
this.cardID = cardID;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "账户{" +
"id=" + id +
", 用户名='" + username + '\'' +
", cardID='" + cardID + '\'' +
", 余额=" + balance +
'}';
}
}
Log类
package com.cqust.pojo;
import java.util.Date;
public class Log {
private int id;
private String name;
private String type;
private double amount;
private String outUser;
private String inUser;
private Date time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public String getOutUser() {
return outUser;
}
public void setOutUser(String outUser) {
this.outUser = outUser;
}
public String getInUser() {
return inUser;
}
public void setInUser(String inUser) {
this.inUser = inUser;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
@Override
public String toString() {
return "Log{" +
"id=" + id +
", name='" + name + '\'' +
", type='" + type + '\'' +
", amount=" + amount +
", outUser='" + outUser + '\'' +
", inUser='" + inUser + '\'' +
", time=" + time +
'}';
}
}
utils层
MyBatisUtils类
package com.cqust.utils;
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 java.io.Reader;
/**
* 工具类
*/
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
//初始化SQLSessionFactory对象
static {
try{
//使用MyBatis提供的Resource类加载MyBatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//构建SQLSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e){
e.printStackTrace();
}
}
//获取SqlSession对象的方法
public static SqlSession getSession(){
//若传入true表示关闭事务控制,自动提交;false表示开启事务控制
return sqlSessionFactory.openSession(true);
}
}
测试层
Test2(测试类)
import com.cqust.pojo.Account;
import com.cqust.pojo.Log;
import com.cqust.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test2 {
@Test
public void addAccountTest(){
SqlSession session = MyBatisUtils.getSession();
System.out.println("正在开户...");
Account account = new Account();
Log log = new Log();
Date date=new Date(System.currentTimeMillis()); //获取当前时间并实例化
// SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //定义时间格式并初始化
// System.out.println(sdf.format(date));
account.setUsername("八戒");
account.setCardID("002");
account.setBalance(99.99);
session.insert("addAccount",account);
log.setName("八戒");
log.setType("addAccount");
log.setAmount(99.99);
log.setTime(date);
session.insert("addLog",log);
System.out.println("开户成功!");
session.close();
}
@Test
public void depositTest(){
SqlSession session = MyBatisUtils.getSession();
System.out.println("正在存款...");
Account account = new Account();
Log log = new Log();
Date date=new Date(System.currentTimeMillis()); //获取当前时间并实例化
account.setBalance(100.00);
account.setCardID("985211");
session.update("deposit",account);
log.setName("Hades");
log.setType("deposit");
log.setAmount(100.00);
log.setTime(date);
session.insert("addLog",log);
System.out.println("存款成功!");
session.close();
}
@Test
public void withdrawalTest(){
SqlSession session = MyBatisUtils.getSession();
System.out.println("正在取款...");
Account account = new Account();
Log log = new Log();
Date date=new Date(System.currentTimeMillis()); //获取当前时间并实例化
account.setBalance(100.00);
account.setCardID("985211");
session.update("withdrawal",account);
log.setName("Hades");
log.setType("withdrawal");
log.setAmount(10.00);
log.setTime(date);
session.insert("addLog",log);
System.out.println("取款成功!");
session.close();
}
@Test
public void transferTest(){
SqlSession session = MyBatisUtils.getSession();
System.out.println("正在转账...");
Account account1 = new Account();
Account account2 = new Account();
Log log = new Log();
Date date=new Date(System.currentTimeMillis()); //获取当前时间并实例化
account1.setBalance(100.00);
account1.setCardID("985211");
session.update("withdrawal",account1);
account2.setBalance(100.00);
account2.setCardID("000");
session.update("deposit",account2);
log.setName("Hades");
log.setType("transfer");
log.setAmount(10.00);
log.setOutUser("Hades");
log.setInUser("ikun");
log.setTime(date);
session.insert("transferLog",log);
System.out.println("转账成功!");
session.close();
}
}
程序运行结果:
实验4:
实验总结:
本次实验主要是对实验4的书写,即对银行转账系统的DAO层的功能改造,主要是对MyBatis的核心配置内容和动态SQL内容的综合运用,其中数据库的时间与显示相差8个小时的问题弄了很久,非常感谢我的老师,不厌其烦地为我一一解答,终于解决了所有的问题,让程序顺利运行。这个版本的代码是初稿,写的非常的粗糙鄙陋,希望后期学到新知识后能进行改进(本人很懒!)。
写在最后:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!
谢谢浏览!