MyBatis在操作数据库时,主要分为8大步骤:
(1) 读取MyBatis配置文件mabatis-config.xml,mabatis-config.xml作为MaBatis的全局配置文件,配置了MyBatis的运行环境等信息,其主要是获取数据库连接。
(2) 加载映射文件Mapper.xml。Mapper.xml即SQL映射文件,该文件配置了操作数据库的SQL语句,需要在mybatis-config.xml中加载才能执行。mybatis-config.xml可以添加多个配置文件,每个配置文件对应数据库中的一张表。
(3) 构建会话工厂。通过MyBatis的环境等配置信息构建会话工厂SqlSessionFactory。
(4) 创建SqlSession对象。由会话工厂创建SqlSession对象。,该对象中包含执行SQL的所有方法。
(5) MyBatis底层定义的一个Executor接口会根据SqlSession传递的参数动态生成SQL语句,同时负责查询缓存的维护。
(6) 根据生成的SQL语句生成MappedStatement对象。
(7) 向MappedStatement输入映射对象,这里的输入参数的映射过程就相当于JDBC编程中对preparedStatement对象设置参数的过程。
(8) 执行SQL语句,对MappedStatement对象返回的结果进行处理。
下面通过一个入门程序来理解。
1.根据学号查询学生信息
(1)这里用sql server数据库。
在SQL Server数据库中,创建一个名为student的数据库,创建一个student表,并插入几条数据。
创建代码:
-
create
database student;
-
use student;
-
create
table student
-
(
-
st_no
int
identity(
1,
1) primary
key ,
-
st_name
varchar(
30)
not
null,
-
sex
varchar(
2)
default
'男'
not
null,
-
tel
varchar(
11),
-
address
varchar(
30),
-
)
-
alter
table student
add
constraint ck_sex
check (sex
in(
'男',
'女'));
-
insert
into student
values(
'张三',
'女',
'13688883333',
'湖南长沙');
-
insert
into student
values(
'李四',
'女',
'13644443333',
'湖南益阳');
-
insert
into student
values(
'李元霸',
'男',
'13512222444',
'湖南衡阳');
-
insert
into student
values(
'张莉莉',
'女',
'13688883333',
'湖南长沙');
-
select *
from student;
(2)在Myeclipse创建一个名为project01的Web项目,将MyBatis的核心jar包、依赖包,以及Sql Server数据库驱动添加到项目的lib目录下。
(3)在src目录下创建log4j.properties文件,内容如下 :
-
# Global logging configuration
-
log4j.rootLogger=ERROR, stdout
-
# MyBatis logging configuration...
-
log4j.logger.cn.swjd=DEBUG
-
# Console output...
-
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
MyBatis默认使用log4j输出日志信息,如果要在控制台查看sql语句,就必须
在src目录下创建log4j.properties文件。
(4)在src目录下创建cn.swjd.entries包,在该包下创建持久化类Student。
-
package cn.swjd.entries;
-
//学生持久化类
-
public
class Student {
-
//主键学号
-
private Integer st_no;
-
//姓名,性别,年龄,电话 ,地址
-
private String st_name, sex, tel, address;
-
public Integer getSt_no() {
-
return st_no;
-
}
-
public void setSt_no(Integer st_no) {
-
this.st_no = st_no;
-
}
-
public String getSt_name() {
-
return st_name;
-
}
-
public void setSt_name(String st_name) {
-
this.st_name = st_name;
-
}
-
public String getSex() {
-
return sex;
-
}
-
public void setSex(String sex) {
-
this.sex = sex;
-
}
-
public String getTel() {
-
return tel;
-
}
-
public void setTel(String tel) {
-
this.tel = tel;
-
}
-
public String getAddress() {
-
return address;
-
}
-
public void setAddress(String address) {
-
this.address = address;
-
}
-
@Override
-
public String toString() {
-
return
"Student [st_no=" + st_no +
", st_name=" + st_name +
", sex="
-
+ sex +
", tel=" + tel +
", address=" + address +
"]";
-
}
-
}
(5)在src目录下。创建cn.swjd.mapper包,在包里创建映射文件StudentMapper.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="cn.swjd.mapper.StudentMapper">
-
<select id="findStudentById" parameterType="Integer" resultType="cn.swjd.entries.Student">
-
select * from student where st_no= #{st_no}
-
</select>
-
</mapper>
说明:<mapper>元素是配置文件的根元素,它包含一个namespace属性,该属性指定了<mapper>的唯一命名空间,通常设置为“包名+SQL映射文件名”的形式。
子元素<select>中的信息是用于执行查询操作的配置,id是唯一标识符。
parameterType:指定传入参数的类型。
resultType:指定返回结果的类型。
#{}:表示一个占位符,相当于jdbc中的?,其里面的内容为接受参数的名称。
(6)在src目录下,创建MyBatis的核心配置文件mybatis-config.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>
-
<environments default="sqlserver">
-
<environment id="sqlserver">
-
<transactionManager type="JDBC"/>
-
<!-- 配置数据库连接池 -->
-
<dataSource type="POOLED">
-
<property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
-
<property name="url" value="jdbc:sqlserver://localhost:1433;DataBaseName=student"/>
-
<property name="username" value="sa"/>
-
<property name="password" value="123"/>
-
</dataSource>
-
</environment>
-
</environments>
-
<mappers>
-
<mapper resource="cn/swjd/mapper/StudentMapper.xml"/>
-
</mappers>
</configuration>
说明:
<environments>下可配置多个运行环境,default属性用于设置默认运行环境。
(7)在src目录下,创建一个cn.swjd.test包,创建测试类MyBatisTest,再编写一个方法findStudentByIdTest(int st_id),并在main方法里调用。
-
package cn.swjd.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 cn.swjd.entries.Student;
-
public
class MyBatisTest {
-
public static void findStudentByIdTest(int st_id) throws Exception{
-
//1.读取配置文件
-
String resource=
"mybatis-config.xml";
-
InputStream inputstream=Resources.getResourceAsStream(resource);
-
//2.根据配置文件构建SqlSessionFactory
-
SqlSessionFactory factory=
new SqlSessionFactoryBuilder().build(inputstream);
-
//3.通过SqlSessionFactory构建SqlSession
-
SqlSession sqlsession=factory.openSession();
-
//4.SqlSession执行映射文件中定义的SQL,并返回其映射结果
-
Student s=sqlsession.selectOne(
"cn.swjd.mapper.StudentMapper.findStudentById",st_id);
-
//打印输出结果
-
System.out.println(s.toString());
-
}
-
public static void main(String args[]) throws Exception{
-
findStudentByIdTest(
1);
-
}
-
-
}
运行结果:
2.根据姓名模糊查询学生信息
修改映射文件StudentMapper.xml,添加一个<select>
<select id="findStudentByName" parameterType="String" resultType="cn.swjd.entries.Student">
select * from student where st_name like '%${value}%'
</select>
这里传入参数为什么不设置为#{}而用${}呢?
假设传入参数在程序里为 String value=”张”;
如果使用的是#{},最终的sql语句就会变成:
select * from student where st_name like ‘’张’’
使用${},最终的sql语句就会变成:
select * from student where st_name like ‘张’
原因:如果使用的是#{},传入参数?就会根据配置文件<select>中parameterType属性(即数据类型)自动变换,如果parameterType="String",就会自动加入’’, 如果parameterType="Integer",就不会加’’。
而使用${} 不管parameterType属性为何值,都不会自动加’’。
在类MyBatisTest,编写一个方法findStudentByNameTest(String value),并在main方法里调用。
-
public static void findStudentByNameTest(String st_name) throws Exception{
-
//1.读取配置文件
-
String resource=
"mybatis-config.xml";
-
InputStream inputstream=Resources.getResourceAsStream(resource);
-
//2.根据配置文件构建SqlSessionFactory
-
SqlSessionFactory factory=
new SqlSessionFactoryBuilder().build(inputstream);
-
//3.通过SqlSessionFactory构建SqlSession
-
SqlSession sqlsession=factory.openSession();
-
//4.SqlSession执行映射文件中定义的SQL,并返回其映射结果
-
List<Student> s=sqlsession.selectList(
"cn.swjd.mapper.StudentMapper.findStudentByName",st_name);
-
/*selectList方法第一个参数为<Mapper>的namespace属性+<select>的id属性,后面接传入参数*/
-
//打印输出结果
-
for(Student stu:s)
-
System.out.println(stu.toString());
-
}
-
public static void main(String args[]) throws Exception{
-
findStudentByNameTest(
"张");
-
}
运行结果:
结果出来了,但是这里有一个问题,使用“${}”拼接字符串,无法防止sql注入问题。
比如这里,如果把方法调用改成:
findStudentByNameTest("1';delete from student where st_no>0;commit; select * from student where st_name like '”);
它竟然可以操作数据库!把表所有内容都删除了。显然,实际项目开发中,是不能出现这种bug的,你永远不知道用户会输入什么东西。
所以,为了安全性,这里不能用${},只能用#{},我们可以用SqlServer中的拼接函数concat()。
修改后:
select * from student where st_name like concat('%',#{value},'%')
修改、删除、增加操作都差不多
相比于查询,就是多了sqlsession.commit()提交事务这一步骤而已
-
<?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="cn.swjd.mapper.StudentMapper">
-
<!-- 根据学号查询学生信息 -->
-
<select id="findStudentById" parameterType="Integer" resultType="cn.swjd.entries.Student">
-
select * from student where st_no= #{st_no}
-
<!-- 根据姓名模糊查询学生信息 -->
-
</select>
-
<select id="findStudentByName" parameterType="String" resultType="cn.swjd.entries.Student">
-
select * from student where st_name like concat('#',#{value},'#')
-
</select>
-
<!-- 更新学生信息 -->
-
<update id="updateStudent" parameterType="cn.swjd.entries.Student"
-
>
-
update student set st_name=#{st_name},sex=#{sex},tel=#{tel},address=#{address} where st_no=#{st_no}
-
</update>
-
<!-- 删除学生信息 -->
-
<delete id="deleteStudent" parameterType="Integer">
-
delete from student where st_no=#{id}
-
</delete>
-
<!-- 增加学生信息 -->
-
<insert id="addStudent" parameterType="cn.swjd.entries.Student">
-
insert into student values (#{st_name},#{sex},#{tel},#{address})
-
</insert>
-
</mapper>
-
package cn.swjd.test;
-
import java.io.IOException;
-
import java.io.InputStream;
-
import java.util.List;
-
-
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 cn.swjd.entries.Student;
-
public
class MyBatisTest {
-
//根据学号查找学生
-
public static void findStudentByIdTest(int st_id) throws Exception{
-
//1.读取配置文件
-
String resource=
"mybatis-config.xml";
-
InputStream inputstream=Resources.getResourceAsStream(resource);
-
//2.根据配置文件构建SqlSessionFactory
-
SqlSessionFactory factory=
new SqlSessionFactoryBuilder().build(inputstream);
-
//3.通过SqlSessionFactory构建SqlSession
-
SqlSession sqlsession=factory.openSession();
-
//4.SqlSession执行映射文件中定义的SQL,并返回其映射结果
-
Student s=sqlsession.selectOne(
"cn.swjd.mapper.StudentMapper.findStudentById",st_id);
-
/*selectOne方法第一个参数为<Mapper>的namespace属性+<select>的id属性,后面接传入参数*/
-
//打印输出结果
-
System.out.println(s.toString());
-
}
-
//根据姓名模糊查找学生
-
public static void findStudentByNameTest(String st_name) throws Exception{
-
//1.读取配置文件
-
String resource=
"mybatis-config.xml";
-
InputStream inputstream=Resources.getResourceAsStream(resource);
-
//2.根据配置文件构建SqlSessionFactory
-
SqlSessionFactory factory=
new SqlSessionFactoryBuilder().build(inputstream);
-
//3.通过SqlSessionFactory构建SqlSession
-
SqlSession sqlsession=factory.openSession();
-
//4.SqlSession执行映射文件中定义的SQL,并返回其映射结果
-
List<Student> s=sqlsession.selectList(
"cn.swjd.mapper.StudentMapper.findStudentByName",st_name);
-
/*selectList方法第一个参数为<Mapper>的namespace属性+<select>的id属性,后面接传入参数*/
-
//打印输出结果
-
for(Student stu:s)
-
System.out.println(stu.toString());
-
}
-
//更新学生信息
-
public static void updateStudent(Student s) throws IOException{
-
//1.读取配置文件
-
String resource=
"mybatis-config.xml";
-
InputStream inputstream=Resources.getResourceAsStream(resource);
-
//2.根据配置文件构建SqlSessionFactory
-
SqlSessionFactory factory=
new SqlSessionFactoryBuilder().build(inputstream);
-
//3.通过SqlSessionFactory构建SqlSession
-
SqlSession sqlsession=factory.openSession();
-
//4.SqlSession执行映射文件中定义的SQL,并返回其映射结果
-
int i = sqlsession.update(
"cn.swjd.mapper.StudentMapper.updateStudent", s);
-
//提交事务
-
sqlsession.commit();
-
if(i>
0){
-
System.out.println(
"更新学号为"+s.getSt_no()+
"学生信息成功!");
-
}
-
}
-
//删除学生信息
-
public static void deleteStudent(int st_no) throws IOException{
-
//1.读取配置文件
-
String resource=
"mybatis-config.xml";
-
InputStream inputstream=Resources.getResourceAsStream(resource);
-
//2.根据配置文件构建SqlSessionFactory
-
SqlSessionFactory factory=
new SqlSessionFactoryBuilder().build(inputstream);
-
//3.通过SqlSessionFactory构建SqlSession
-
SqlSession sqlsession=factory.openSession();
-
//4.SqlSession执行映射文件中定义的SQL,并返回其映射结果
-
int i = sqlsession.delete(
"cn.swjd.mapper.StudentMapper.deleteStudent", st_no);
-
//5.提交事务
-
sqlsession.commit();
-
if(i>
0){
-
System.out.println(
"删除学号为"+st_no+
"的学生信息成功!");
-
}
-
-
}
-
//增加学生信息
-
public static void addStudent(Student s) throws IOException{
-
//1.读取配置文件
-
String resource=
"mybatis-config.xml";
-
InputStream inputstream=Resources.getResourceAsStream(resource);
-
//2.根据配置文件构建SqlSessionFactory
-
SqlSessionFactory factory=
new SqlSessionFactoryBuilder().build(inputstream);
-
//3.通过SqlSessionFactory构建SqlSession
-
SqlSession sqlsession=factory.openSession();
-
//4.SqlSession执行映射文件中定义的SQL,并返回其映射结果
-
int i = sqlsession.insert(
"cn.swjd.mapper.StudentMapper.addStudent", s);
-
//5.提交事务
-
sqlsession.commit();
-
if(i>
0){
-
System.out.println(
"添加一条学生信息成功!");
-
}
-
}
-
public static void main(String args[]) throws Exception{
-
Student s=
new Student();
-
s.setSt_name(
"李云瑞");
-
s.setSex(
"男");
-
addStudent(s);
-
}
-
-
}