mybatis下载
mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases。 可从该地址下载mybatis最新框架。
下载之后解压缩:
案例需求
1 根据用户id查询y一个用户信息
2 根据用户名模糊查询用户信息列表
3 添加用户信息
4 修改用户信息
5 删除用户信息
MyBatis入门程序配置
1)新建数据库mybatis
2)新建表user
CREATE TABLE `NewTable` (
`id` int(4) NOT NULL AUTO_INCREMENT ,
`name` varchar(7) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
PRIMARY KEY (`id`)
)ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci;
3)新建项目mabatis_demo01(以web项目为例)
4)导入jar包
工程所需加入的Jar包有mybatis核心包、依赖包和mysql数据驱动包。
5)在工程下新建一个源码包config,并在其中创建一个日志记录文件–log4j.properties
log4j.properties文件:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# 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作为输出日志信息。
6)在config源码包中新建MyBatis的配置文件SqlMapConfig.xml
SqlMapConfig.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>
<!-- 和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>
</configuration>
注意:等后面mybatis和Spring两个框架整合之后,environments的配置将被废除。
7)创建一个实体类User
在包com.oak.domain下新建实体类User
User类内容为:
public class User {
//user的id
private Integer id;
//user的name
private String name;
public User() {
super();
}
public User(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
8)在源码包config下新建一个包sqlmap,在其中创建映射文件user.xml
在该包内新建user.xml,此文件即sql映射文件,文件中配置了操作数据库的sql语句,此文件需要在SqlMapConfig.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="test">
</mapper>
namespace:即命名空间,其用于隔离sql语句(即不同sql映射文件中的两个相同id的sql语句如何来区分),这是当前的作用,后面会讲另一层非常重要的作用。
9)加载映射文件。mybatis框架需要加载映射文件,将user.xml添加在SqlMapConfig.xml中
在SqlMapConfig.xml配置文件中添加如下配置信息
<mappers>
<!-- resource是基于classpath(源码包)来查找的 -->
<mapper resource="sqlmap/user.xml"/>
</mappers>
10)根据id查询用户信息
在user.xml映射文件中添加如下配置:
<!-- 根据id获取用户信息 -->
<select id="findUserById" parameterType="int" resultType="com.oak.domain.User">
select * from `user` where id=#{id};
</select>
-
< select>标签用于定义查询语句,相应的还有增删改
-
parameterType:参数的数据类型,即定义输入到sql中的映射类型。
-
resultType:结果的数据类型,如果是pojo则应该给出全路径。
-
#{id}表示使用PreparedStatement设置占位符号并将输入变量id传到sql中。说白点,#{}作用就是占位符,相当于JDBC中的?。
11)在com.oak.test包中新建MyBatisTest类,在类中新建测试方法:
@Test
public void findUserById() throws IOException {
// 第一步,创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 第二步,加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 第三步,创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 第四步,创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第五步,使用SqlSession对象执行查询,得到User对象
// 第一个参数:执行查询的StatementId
User user = sqlSession.selectOne("findUserById", 1);
// 第六步,打印结果
System.out.println(user);
// 第七步,释放资源,每一个sqlSession就是一个连接
sqlSession.close();
}
以上步骤过于繁琐,而一般来讲工厂对象一般在实际开发是单例的,并不需要频繁地创建,所以我们在此给SqlSessionFactory定义为单例:
public class MyBatisTest {
// 工厂对象一般在我们的系统中是单例的
private SqlSessionFactory sqlSessionFactory=null;
/**
* Junit中的基本注解,不是AOP中的那个,
* 表示在任意使用@Test注解标注的public void方法执行之前执行
* @throws IOException
*/
@Before
public void init() throws IOException{
// 第一步,创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 第二步,加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 第三步,创建SqlSessionFactory对象
sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void findUserById() throws IOException {
// 第四步,创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第五步,使用SqlSession对象执行查询,得到User对象
// 第一个参数:执行查询的StatementId
User user = sqlSession.selectOne("findUserById", 1);
// 第六步,打印结果
System.out.println(user);
// 第七步,释放资源,每一个sqlSession就是一个连接
sqlSession.close();
}
}
执行测试:
12)根据用户名称模糊查询用户信息列表
在user.xml中添加如下配置:
<!-- 根据名称模糊查询用户信息列表 -->
<select id="findUserByName" parameterType="String" resultType="com.oak.domain.User">
select * from `user` where name like #{name}
</select>
如果查询结果返回的是List集合,那么resultType只需要设置为List集合中的一个元素的数据类型即可。
在测试类中测试:
@Test
public void findUserByName(){
//创建SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//执行查询
List<User> list=sqlSession.selectList("findUserByName","%s%");
System.out.println(list);
sqlSession.close();
}
运行测试,查看结果:
使用${value}字符串拼接指令完成此任务
修改xml中的sql为:
<!-- 根据名称模糊查询用户信息列表 -->
<select id="findUserByName" parameterType="String" resultType="com.oak.domain.User">
select * from `user` where name like '${value}'
</select>
$ {value}表示使用参数将$ {value}替换,做字符串的拼接,${}为字符串拼接指令。注意:如果是取简单数据类型的参数,括号中的值必须为value。
直接运行上述测试方法:
很明显这种方式在实际开发中是不建议使用的,因为无法防止SQL注入,建议使用#{ }。
小结
1)#{}和${}
#{}:表示一个占位符号,可以很好地去避免sql注入。其原理是将占位符位置的整个参数和sql语句两部分提交给数据库,数据库去执行sql语句,去表中匹配所有的记录是否和整个参数是否一致。
#{}要获取输入参数的值:
-
如果输入参数是简单数据类型,则#{}中可以写value或其它名称。
-
如果输入参数是pojo对象类型,则#{}可通过OGNL方式去获取,表达式就是属性.属性.属性…方式。
$ {}:表示一个sql拼接符号,其原理是在向数据库发出sql之前去拼接好sql再提交给数
据库执行。
${}要获取输入参数的值:
-
如果输入参数是简单数据类型,则${}中只能写value。
-
如果输入参数是pojo对象类型,则${}可通过OGNL方式去获取,表达式就是属性.属性.属性…方式。
一般情况下建议使用#{},特殊情况下必须要用${},比如:
-
动态拼接sql中动态组成排序字段,要通过$ {}将排序字段传入sql中。
-
动态拼接sql中动态组成表名,要通过$ {}将表名传入sql中。
2)parameterType和resultType
parameterType:指定输入参数类型,mybatis通过ognl方式从输入对象中获取参数值拼接在sql中。
resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。
3)selectOne()和selectList()方法
selectOne:查询一条记录,如果使用selectOne查询多条记录则抛出异常
selectList:可以查询一条或多条记录。
13)添加一条用户信息
在xml配置文件中添加配置:
<!-- 添加一条信息 -->
<insert id="addUser" parameterType="com.oak.domain.User">
insert into `user` values(null,#{name})
</insert>
如果输入参数类型是po,那么#{}中的名称就是po类中的属性,不能随便定义。
测试类中测试
@Test
public void addUser(){
//创建SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.insert("addUser", new User(null, "ww"));
sqlSession.close();
}
查看控制台:
查看数据库:
虽然发出了sql语句,但是事务并没将其提交,而是回滚了。故User对象是无法插入到数据库user表中的。
应该在执行之后进行事务提交。修改测试方法为:
@Test
public void addUser(){
//创建SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.insert("addUser", new User(null, "ww"));
sqlSession.commit();
sqlSession.close();
}
查看控制台:
查看数据库:
事务已提交,可发现数据库user表中插入一条记录。
14)MySQL自增主键返回
想要得到MySQL数据库给我们生成的主键id,即获取主键。
这里要用到MySQL数据库中的一个函数:
- LAST_INSERT_ID():返回auto_increment自增列新记录id值。该函数是在当前事务下取到你最后生成的id值,而我们应知道查询操作是没有开启事务的,增删改操作是需要开启事务的。
为了获取自动主键,更改user.xml中的addUser为:
<!-- 添加一条信息 返回自动增长主键 -->
<insert id="addUser" parameterType="com.oak.domain.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into `user` values(null,#{name})
</insert>
-
keyProperty:返回的主键存储在po中的哪个属性(即其对应po的主键属性)。获取主键,实际上是将主键取出来之后封装到了po的主键属性当中。
-
resultType:返回的主键是什么类型(即其对应pojo的主键的数据类型)。
-
order:selectKey的执行顺序,是相对于insert语句来说的,由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为AFTER。
在测试类中修改测试方法为:
@Test
public void addUser(){
//创建SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//只给name赋值
User user=new User(null, "zl");
sqlSession.insert("addUser", user);
System.out.println("或者自动增长主键:"+user.getId());
sqlSession.commit();
sqlSession.close();
}
查看测试结果:
查看数据库:
15)删除信息
在user.xml中添加
<!-- 删除用户 -->
<delete id="deleteUser" parameterType="int">
delete from `user` where id=#{id}
</delete>
在测试类中测试:
@Test
public void delUser(){
//创建SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.delete("deleteUser",1);
sqlSession.commit();
sqlSession.close();
}
16)修改信息
在user.xml中添加修改:
<!-- 修改信息 -->
<update id="updateUser" parameterType="com.oak.domain.User">
update `user` set name=#{name} where id=#{id}
</update>
测试:
@Test
public void updateUser(){
//创建SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.update("updateUser",new User(2, "李四"));
sqlSession.commit();
sqlSession.close();
}
MyBatis解决了JDBC编程的问题
-
数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库连接。 -
Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。 -
向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决: MyBatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。 -
对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决: MyBatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。