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);
}
}