为什么学Mybatis?
- 目前最主流的持久层框架为hibernate与mybatis,而且国内目前情况使用Mybatis的公司比hibernate要多。
- Hibernate学习门槛不低,要精通门槛更高。门槛高在怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate缓存与数据加载策略方面需要你的经验和能力都很强才行。国内目前前的情况精通hibernate技术大牛非常少。
- sql优化方面,Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。当然了,Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。说得更深入一些,如果有个查询要关联多张表,比如5张表,10张表时,而且,我们要取的字段只是其中几张表的部分字段。这时用hibernate时就会显得非常力不从心。就算用hibernate的sqlquery,后续的维护工作也会让人发狂。
需求列表
根据用户ID查询用户信息
根据用户名查找用户列表
添加用户
修改用户
删除用户
- 工程搭建
- 导入依赖jar包
- 配置SqlMapConfig.xml
- 配置log4j.properties
- 编写pojo类
- 配置sql查询的映射文件,加载映射文件,在SqlMapConfig.xml配置mappers节点
项目目录
核心配置文件(右键项目 ——> Source Folder ——> 新建conf文件夹)
(在conf文件夹中新建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>
<!-- 别名的定义 -->
<typeAliases>
<!-- 定义单个别名 -->
<!-- <typeAlias alias="user" type="com.zwk.pojo.User"/> -->
<!-- 定义别名:包描述,别名就是类的全称不区分大小写 推荐这种方式-->
<package name="com.zwk.pojo.User"/>
</typeAliases>
<!-- 和spring整合后 environments配置将废除,Spring会覆盖这个配置 -->
<environments default="development"> // 默认的环境ID(比如:default:"development")development : 开发模式 work : 工作模式 test:测试环境
<environment id="development"> // 每个 environment 元素定义的环境 ID(比如:id=”development”)。
<!-- 使用jdbc事务管理 -->
<!-- 事务管理器有两种:type="[ JDBC | MANAGED ]":
JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。
MANAGED :这个配置从来都不提交和回滚一个连接,而是让容器来管理事务的整个生命周期(比如JEE应用服务的上下文)。
默认情况下他会关闭连接,然而一些容器并不希望这样,因此需要将closeConnection属性设置为false来阻止它默认的关闭行为。 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED"> // 三种内建的数据源类型:type=[ UNPOOLED | POOLED | JNDI ]
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
<!-- 测试环境 -->
<environment id="test">
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 有三种方式 resource、class、url -->
<mappers>
<!-- resource方式 加载一个映射文件 在根目录下 -->
<mapper resource="mybatis/user.xml"/>
<mapper resource="mybatis/UserMapper.xml"/>
<!-- class方式加载 映射文件,类加载器规则:
1、映射文件必需与接口文件同一目录下
2、映射文件的名称必需与接口名一致
-->
<!-- <mapper class="com.itheima.mybatis.mapper.UserMapper"/> -->
<!-- 映射文件的包扫描,规则(推荐使用):
扫描 com.itheima.mybatis.mapper 包下所有的映射文件
1、映射文件必需与接口文件同一目录下
2、映射文件的名称必需与接口名一致
-->
<!-- <package name="com.itheima.mybatis.mapper"/> -->
<!-- url方式加载映射文件 -->
<mapper url="D://user.xml"/>
</mappers>
</configuration>
jdbc.properties(在conf文件中新建user.xml)
注意:数据库账号和密码是否需要更改
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
映射文件(在conf文件中新建User.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语句的,相当于java包,后续有重要作用
#{}:占位符,相当于jdbc的? 如果parameterType为基本数据类型时参数可随意填写,推荐使用
${}:字符串拼接指令,如果入参为普通数据类型时,括号里只能写value
-->
<!-- 在 SqlMapConfig.xml 中已经设置了别名 为user -->
<mapper namespace="user">
<!-- id:sql语句的唯一标识,sql id
parameterType:入参数据类型
resultType:查询结果的数据类型,这里为了好理解就不使用别名了。若要使用别名,只需把 com.zwk.pojo.User 改为 user 就行了
-->
<select id="getUserById" parameterType="int" resultType="com.zwk.pojo.User">
SELECT * FROM USER WHERE id = #{id1}
</select>
<!-- resultType:返回结果为集合时,只需设置为集合中每一个元素的数据类型就可 -->
<select id="getUserByUserName" parameterType="string" resultType="com.zwk.pojo.User">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
<insert id="insertUser" parameterType="com.zwk.pojo.User">
<!-- sql表达式也可以写成这样 在sqlyog小海豚中右键数据库中的表,选择粘贴sql语句--> INSERT INTO / UPDATE / DELETE FROM / SELECT
INSERT INTO `user`
(`username`,
`birthday`,
`sex`,
`address`
)
VALUES (#{username},
#{birthday},
#{sex},
#{address});
</insert>
<!-- 主键返回第一种方式:useGeneratedKeys,同时指定keyProperty -->
<insert id="insertUserKey" parameterType="com.zwk.pojo.User" useGeneratedKeys="true" keyProperty="id">
<!-- selectKey配置主键返回
order:指定执行时机
keyProperty:查询到的主键给谁
resultType:主键的数据类型
-->
<!-- 返回主键的第一种方式 -->
<!-- <selectKey order="AFTER" keyProperty="id" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey> -->
INSERT INTO `user`
(`username`,
`birthday`,
`sex`,
`address`)
VALUES (#{username},
#{birthday},
#{sex},
#{address});
</insert>
<!-- 主键返回第二种方式:useGeneratedKeys,同时指定keyProperty -->
<insert id="insertUserUUID" parameterType="com.zwk.pojo.User" useGeneratedKeys="true" keyProperty="id">
<!-- selectKey配置主键返回
order:指定执行时机
keyProperty:查询到的主键给谁
resultType:主键的数据类型
总结:配置了UUID时,useGeneratedKeys="true" keyProperty="id"两个属性会失效
-->
<selectKey order="BEFORE" keyProperty="uuid2" resultType="string">
SELECT UUID()
</selectKey>
INSERT INTO `user`
(`username`,
`birthday`,
`sex`,
`address`,
`uuid2`)
VALUES (#{username},
#{birthday},
#{sex},
#{address},
#{uuid2});
</insert>
<update id="updateUser" parameterType="com.zwk.pojo.User">
UPDATE `user`
SET `username` = #{username}
WHERE `id` = #{id};
</update>
<delete id="deleteUser" parameterType="int">
DELETE
FROM `user`
WHERE `id` = #{id};
</delete>
</mapper>
log4j.properties(
在conf文件中新建
log4j.properties
)
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info, stdout
User.java(在src目录下新建包 com.zwk.pojo.User , 在此包下新建User.java)
注意:
com.zwk.pojo.User包名与User.xml映射文件中的包名是一致的,还有
SqlMapConfig.xml 配置中的别名中指向 的包名。
/**
* 用户信息业务实体
* @author Steven
*
*/
public class User {
private Integer id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
private String uuid2; // UUID
set ... 省略
get ...
创建数据库,根据User.java创建mybatis数据库,表名为user (过程略)
测试类 MyBatisTest.java ( com.zwk.test
)
package com.zwk.test;
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.Test;
import com.zwk.pojo.User;
import com.zwk.utils.SqlSessionFactoryUtils;
public class MybatisTest {
@Test
public void getUserId() throws IOException{
// 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 查找配置文件创建输入流
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 加载配置文件,创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sfb.build(inputStream);
// 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行查询,参数一:要查询的statementId ,
//参数二:sql语句入参 user.getUserById:user代表映射文件user.xml getUserById sql语句的唯一标识
User user = sqlSession.selectOne("user.getUserById", 1);
// 输出查询结果
System.out.println(user);
// 释放资源
sqlSession.close();
}
@Test
public void getUserName(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
List<User> selectList = sqlSession.selectList("user.getUserByUserName", "z");
for (User user : selectList) {
System.out.println(user);
}
//释放资源
sqlSession.close();
}
//插入语句
@Test
public void insertUser(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
User user = new User();
user.setBirthday(new Date());
user.setSex("男");
user.setUsername("张三");
user.setAddress("深圳");
int i = sqlSession.insert("user.insertUser", user);
System.out.println(i); // i > 0 时,表示程序运行成功
// 注意:执行DML操作时 必须要提交事务
sqlSession.commit();
sqlSession.close();
}
//主键返回
@Test
public void insertUserKey(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
User user = new User();
user.setBirthday(new Date());
user.setSex("男");
user.setUsername("王五");
user.setAddress("深圳");
int i = sqlSession.insert("user.insertUserKey", user);
System.out.println(i);
//提交事务
sqlSession.commit();
sqlSession.close();
}
//设置属性UUID
@Test
public void insertUserUUID(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
User user = new User();
user.setBirthday(new Date());
user.setSex("男");
user.setUsername("赵六");
user.setAddress("深圳");
int i = sqlSession.insert("user.insertUserUUID", user);
System.out.println(i);
System.out.println(user);
//提交事务
sqlSession.commit();
sqlSession.close();
}
//修改用户
@Test
public void updateUser(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
User user = new User();
user.setId(1);
user.setUsername("小明");
int i = sqlSession.update("user.updateUser", user);
System.out.println(i);
System.out.println(user);
//提交事务
sqlSession.commit();
sqlSession.close();
}
//删除用户
@Test
public void deleteUser(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
User user = new User();
user.setId(3);
int i = sqlSession.delete("user.deleteUser", user);
System.out.println(i);
System.out.println(user);
//提交事务
sqlSession.commit();
sqlSession.close();
}
}
工具类SqlSessionFactoryUtils (com.zwk.utils)
package com.zwk.utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class SqlSessionFactoryUtils {
private static SqlSessionFactory sqlSessionFactory = null;
static{
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 查找配置文件创建输入流
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 加载配置文件,创建SqlSessionFactory对象
if (sqlSessionFactory == null) {
sqlSessionFactory = sfb.build(inputStream);
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}