本文分享一下,Mybatis的一些入门案例;
为什么不用JDBC方式来操作数据库,而使用类似于Mybatis的框架呢?
1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
一、需求:
根据用户id查询一个用户信息
根据用户名称模糊查询用户信息列表
添加用户
更新用户
删除用户
二、环境搭建
第一、创建maven工程,添加mybatis依赖、mysql驱动等依赖,pom文件如下;
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xingej.mybatis</groupId> <artifactId>itcast-mybatis</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>itcast-mybatis</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency> <!-- mybatis依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- log4j 日志依赖 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> </project>
第二、添加SqlMapConfig.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> <!-- 和spring整合后 environments配置将废除--> <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/mybatis?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments> <mappers> <mapper resource="sqlMap/User.xml"/> </mappers> </configuration>
第三、创建po类
package com.xingej.mybatis.po;
import java.util.Date;
/**
* po类,就是属性+get/set方法
*
* @author erjun
*
*/
public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
+ address + "]";
}
}第四、编写po类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">
<!-- namespace命名空间,为了对sql语句进行隔离,方便管理 ,mapper开发dao方式,使用namespace有特殊作用 -->
<mapper namespace="test">
<!-- 在mapper.xml文件中配置很多的sql语句,执行每个sql语句时,封装为MappedStatement对象
mapper.xml以statement为单位管理sql语句
-->
<!-- 根据id查询用户信息 -->
<!--
id:唯一标识 一个statement
#{}:表示 一个占位符,如果#{}中传入简单类型的参数,#{}中的名称随意
parameterType:输入 参数的类型,通过#{}接收parameterType输入 的参数
resultType:输出结果 类型,不管返回是多条还是单条,指定单条记录映射的pojo类型
-->
<select id="findUserById" parameterType="int" resultType="com.xingej.mybatis.po.User">
SELECT * FROM USER WHERE id= #{id}
</select>
<!-- 根据用户名称查询用户信息,可能返回多条
${}:表示sql的拼接,通过${}接收参数,将参数的内容不加任何修饰拼接在sql中。
${}方式的缺点:不能防止sql的注入;select * from user where name like ‘xiaoming‘ or ‘1=1‘
这条语句,始终成立,后面的‘ or ‘1= 就是sql注入;
有的时候,软件在交付的时候,会进行sql注入的校验。
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.xingej.mybatis.po.User">
select * from user where username like ‘%${value}%‘
</select>
<!-- 添加用户
parameterType:输入 参数的类型,User对象 包括 username,birthday,sex,address
#{}接收pojo数据,可以使用OGNL解析出pojo的属性值
#{username}表示从parameterType中获取pojo的属性值
selectKey:用于进行主键返回,定义了获取主键值的sql
order:设置selectKey中sql执行的顺序,相对于insert语句来说
keyProperty:将主键值设置到哪个属性
resultType:select LAST_INSERT_ID()的结果 类型
-->
<insert id="insertUser" parameterType="com.xingej.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
INSERT INTO USER(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- mysql的uuid生成主键 -->
<!-- <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="string">
select uuid()
</selectKey>
INSERT INTO USER(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert> -->
<!-- oracle
在执行insert之前执行select 序列.nextval() from dual取出序列最大值,将值设置到user对象 的id属性
-->
<!-- <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="int">
select 序列.nextval() from dual
</selectKey>
INSERT INTO USER(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert> -->
<!-- 用户删除 -->
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete>
<!-- 用户更新
要求:传入的user对象中包括 id属性值
-->
<update id="updateUser" parameterType="com.xingej.mybatis.po.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>补充说明:
三、编写测试用例
package com.xingej.mybatis.first;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
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 org.junit.Before;
import org.junit.Test;
import com.xingej.mybatis.po.User;
public class MybatisFirst {
// 声明一个全局的会话工厂
SqlSessionFactory sqlSessionFactory = null;
// 创建session工厂
@Before
public void init() throws IOException {
// 1、配置文件(SqlMapConfig.xml)
String resource = "SqlMapConfig.xml";
// 2、加载配置文件,转换成流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 3、创建会话工厂SessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
// 根据用户ID查询用户(得到单条记录)
@Test
public void testFindUserById() {
// 1、通过session工厂来创建一个session
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2、通过session会话来操作数据库
// 第一个参数:statement位置:就是namespace + statement的id
// 第2个参数:就是你传入的参数
User user = null;
try {
user = sqlSession.selectOne("test.findUserById", 1);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
System.out.println("----user-----:\t" + user);
}
// 根据用户名称来查询,
// 返回结果是List类型
// 支持模糊查询
@Test
public void testFindUserByName() {
// 1、获取session会话
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2、操作数据库
List<User> users = null;
try {
users = sqlSession.selectList("test.findUserByName", "小明");
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
System.out.println("----->:\t" + users.get(2).getUsername());
}
// 插入一条记录
@Test
public void testInsertUser() {
// 1、通过session工厂来创建一个session
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2、通过session会话来操作数据库
User user = new User();
user.setAddress("北京");
user.setBirthday(new Date());
user.setSex("1");
user.setUsername("浪子燕青");
try {
sqlSession.insert("test.insertUser", user);
// 提交事务,千万别忘记
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
System.out.println("----user-----:\t" + user);
}
// 更新一条记录
@Test
public void testUpdateUser() {
// 1、通过session工厂来创建一个session
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2、通过session会话来操作数据库
User user = new User();
user.setId(16);
user.setAddress("北京");
user.setBirthday(new Date());
user.setSex("1");
user.setUsername("故、新");
try {
sqlSession.update("test.updateUser", user);
// 提交事务,千万别忘记
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
System.out.println("----user-----:\t" + user);
}
// 删除一条记录
@Test
public void testDeleteUser() {
// 1、通过session工厂来创建一个session
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2、通过session会话来操作数据库
try {
sqlSession.update("test.deleteUser", 26);
// 提交事务,千万别忘记
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}总结:
1、SqlMapConfig.xml 文件
是mybatis全局配置文件,只有一个,名称不固定的,主要mapper.xml,mapper.xml中配置 sql语句
2、mapper.xml文件
mapper.xml是以statement为单位进行配置。(把一个sql称为一个statement),satatement中配置 sql语句、parameterType输入参数类型(完成输入映射)、resultType输出结果类型(完成输出映射)。
还提供了parameterMap配置输入参数类型(过期了,不推荐使用了)
还提供resultMap配置输出结果类型(完成输出映射),通过resultMap完成复杂数据类型的映射(一对多,多对多映射)
3、#{} 符号说明:
表示一个占位符,向占位符输入参数,mybatis自动进行java类型和jdbc类型的转换。
程序员不需要考虑参数的类型,比如:传入字符串,mybatis最终拼接好的sql就是参数两边加单引号。
#{}接收pojo数据,可以使用OGNL解析出pojo的属性值
4、${} 符号说明:
表示sql的拼接,通过${}接收参数,将参数的内容不加任何修饰拼接在sql中。
${}也可以接收pojo数据,可以使用OGNL解析出pojo的属性值
缺点:不能防止sql注入。
例如:select * from user where name like ‘xiaoming‘ or ‘1=1‘
这条语句,始终成立,后面的 ‘ or ‘1= 就是sql注入
代码已经上传到git上:
https://github.com/xej520/xingej-mybatis
本文出自 “XEJ分布式工作室” 博客,请务必保留此出处http://xingej.blog.51cto.com/7912529/1979119
原文:http://xingej.blog.51cto.com/7912529/1979119