Mybatis(持久层的框架),注入的三种方式
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL(灵活)、存储过程(PLSQL模块化的组件,数据库的一部分)以及高级映射(表映射为Bean也可以将Bean映射为表)。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口(框架的思想都是面向接口来编程)和 Java 的 POJO(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
Mybatis 是一个持久层的架构,是 apache 下的顶级项目。
Mybatis 原先是托管在 googlecode 下,再后来是托管在 Github 上。
Mybatis 让程序员将主要的精力放在 sql 上,通过 Mybatis 提供的映射方式,自由灵活生成(半自动,大部分需要程序员编写 sql )满足需要 sql 语句。
Mybatis 可以将向 preparedStatement 中的输入参数自动进行输入映射,将查询结果集灵活的映射成 java 对象。(输出映射)
Mybatis 框架结构图
image说明:
- SqlMapConfig.xml (Mybatis的全局配置文件,名称不定)配置了数据源、事务等 Mybatis 运行环境
- Mapper.xml 映射文件(配置 sql 语句)
- SqlSessionFactory (会话工厂)根据配置文件配置工厂、创建 SqlSession
- SqlSession (会话)面向用户的接口、操作数据库(发出 sql 增删改查)
- Executor (执行器)是一个接口(基本执行器、缓存执行器)、SqlSession 内部通过执行器操作数据库
- Mapped Statement (底层封装对象)对操作数据库存储封装,包括 sql 语句、输入参数、输出结果类型
Mybatis工程需要引用Maven的本地仓库,关于Maven本地仓库的配制可以参考
地址:https://www.jianshu.com/p/e351f8e22c9a
Mybatis入门程序
1、需求
实现以下功能:
- 根据用户id查询一个用户信息
- 根据用户名称模糊查询用户信息列表
- 添加用户
- 更新用户
- 删除用户
2、环境
- java 环境 :jdk1.8.0_77
- 开发工具 : IDEA 2016.1
- 数据库 : MySQL 5.7
- Mybatis 运行环境( jar 包)
- MySQL 驱动包
- 其他依赖包
数据库表结构如下:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES (1, '王五', NULL, '2', NULL);
INSERT INTO `user` VALUES (10, '张三', '2014-7-10', '1', '北京市');
INSERT INTO `user` VALUES (16, '张小明', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES (22, '陈小明', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES (24, '张三丰', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES (25, '陈小明', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES (26, '王五', NULL, NULL, NULL);
INSERT INTO `user` VALUES (28, '陈小明111', '2017-9-14', '1', '式');
INSERT INTO `user` VALUES (29, 'tom123', '2018-1-19', '1', 'shenyang');
INSERT INTO `user` VALUES (30, 'tom123', '2018-1-19', '1', 'shenyang');
INSERT INTO `user` VALUES (31, 'aabbcc', '2018-6-12', 'm', 'neusoft');
Spring的依赖注入方式有几种
- 接口注入
- 构造器注入
- 属性注入(访问器注入)
Mapper接口与Mapper.xml文件的绑定的规则 - 方法名一定要与id相同
- 方法的输入参数的类型要与parameterType的类型一样
- 方法的返回值类型一定要与resultType的类型一样
1.创建一个Maven工程
2.在pom.xml中添加项目的依赖库(mybatis)
<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.foreknow</groupId>
<artifactId>foreknow_mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>foreknow_mybatis</name>
<description>foreknow_mybatis</description>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<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.38</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
3.需要在resources中添加配制文件:db.properties、log4j.properties、SqlMapConfig.xml(Mybatis的核心配制文件)
db.properties配制
#jdbc.driver=oracle.jdbc.driver.OracleDriver
#jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl
#jdbc.username=scott
#jdbc.password=tiger
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybaits?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=
log4j.properties配制
# Global logging configuration
#\u5728\u5f00\u53d1\u73af\u5883\u4e0b\u65e5\u5fd7\u7ea7\u522b\u8981\u8bbe\u7f6e\u6210DEBUG\uff0c\u751f\u4ea7\u73af\u5883\u8bbe\u7f6e\u6210info\u6216error
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
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>
<!-- 加载属性文件 -->
<properties resource="db.properties">
</properties>
<!-- 全局配置参数,需要时再设置 -->
<!-- <settings>
</settings> -->
<!--起别名 -->
<typeAliases>
<!-- <typeAlias type="com.neusoft.mybatis.pojo.User" alias="User"/> -->
</typeAliases>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis-->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理-->
<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>
<!-- 加载 映射文件 -->
<mappers>
<mapper resource="mapper/User.xml" />
</mappers>
</configuration>
4.创建User.java
package com.foreknow.bean;
import java.util.Date;
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;
}
}
5.创建一个映射(Mapper)文件对数据库进行操作User.xml
mybatis中为每一个映射文件添加一个namespace,这样不同的映射文件中sql语句的id相同也不会有冲突,只要定义在映射文件中的sql语句在该映射文件中id唯一就可以
<?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进行分类化管理 并没有真实的test接口-->
<mapper namespace="test">
<!--
Java代码:
public User findUserById(int id)
id:唯一标识 相当于方法的名称
parameterType:输入参数的类型 相当于方法的参数类型
resultType:方法返回值的类型 注意:全路径(包名+类名)
#{id}:相当于一个占位符
-->
<select id="findUserById" parameterType="int" resultType="com.foreknow.bean.User" >
select * from user where id=#{id}
</select>
<!-- public void insertUser(User user) -->
<insert id="insertUser" parameterType="com.foreknow.bean.User">
insert into User(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
<!--
${value}表示拼接sql字符串
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.foreknow.bean.User">
select * from user where username like '%${value}%'
</select>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<update id="updateUser" parameterType="com.foreknow.bean.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>
6.创建JUnit测试类
package com.foreknow.mybatis_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.foreknow.bean.User;
public class MybatisUserTest {
@Test
public void findUserByIdTest() throws IOException {
String resource = "SqlMapConfig.xml";
//如何对SqlMapConfig.xml读取并解析
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建一个会话工厂(SqlSessionFactory),传入mybatis中的配制信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取到SqlSession对象,作用是操作数据库
SqlSession sqlSession = sqlSessionFactory.openSession();
//关联User.xml文件进行操作
User user = sqlSession.selectOne("test.findUserById", 1);
System.out.println("---------"+user.getUsername()+"-----------");
//释放资源
sqlSession.close();
}
@Test
public void insertUserTest() throws IOException {
String resource = "SqlMapConfig.xml";
//如何对SqlMapConfig.xml读取并解析
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建一个会话工厂(SqlSessionFactory),传入mybatis中的配制信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取到SqlSession对象,作用是操作数据库
SqlSession sqlSession = sqlSessionFactory.openSession();
//关联User.xml文件进行操作
User user = new User();
user.setUsername("tom_test");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("foreknow");
sqlSession.insert("test.insertUser", user);
//提交事物
sqlSession.commit();
//释放资源
sqlSession.close();
}
@Test
public void findUserByNameTest() throws IOException {
String resource = "SqlMapConfig.xml";
//如何对SqlMapConfig.xml读取并解析
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建一个会话工厂(SqlSessionFactory),传入mybatis中的配制信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取到SqlSession对象,作用是操作数据库
SqlSession sqlSession = sqlSessionFactory.openSession();
//关联User.xml文件进行操作
List<User> list = sqlSession.selectList("test.findUserByName", "张");
System.out.println(list.size());
//释放资源
sqlSession.close();
}
@Test
public void deleteUserTest() throws IOException {
String resource = "SqlMapConfig.xml";
//如何对SqlMapConfig.xml读取并解析
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建一个会话工厂(SqlSessionFactory),传入mybatis中的配制信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取到SqlSession对象,作用是操作数据库
SqlSession sqlSession = sqlSessionFactory.openSession();
//关联User.xml文件进行操作
sqlSession.delete("test.deleteUser", 33);
sqlSession.commit();
//释放资源
sqlSession.close();
}
@Test
public void updateUserTest() throws IOException {
String resource = "SqlMapConfig.xml";
//如何对SqlMapConfig.xml读取并解析
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建一个会话工厂(SqlSessionFactory),传入mybatis中的配制信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取到SqlSession对象,作用是操作数据库
SqlSession sqlSession = sqlSessionFactory.openSession();
//关联User.xml文件进行操作
User user = new User();
user.setId(32);
user.setUsername("tom_test123");
user.setBirthday(new Date());
user.setSex("0");
user.setAddress("fffff");
sqlSession.update("test.updateUser", user);
sqlSession.commit();
//释放资源
sqlSession.close();
}
}
总结:
parameterType:指定输入参数类型,mybatis 从输入对象中获取参数值拼接在 sql 中。
resultType:指定输出结果类型,mybatis 将 sql 查询结果的一行记录数据映射为 resultType 指定类型的对象。
Sqlsession 的使用范围
SqlSession 中封装了对数据库的操作,如:查询、插入、更新、删除等。
通过 SqlSessionFactory 创建 SqlSession,而 SqlSessionFactory 是通过 SqlSessionFactoryBuilder 进行创建。
1、SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 用于创建 SqlSessionFacoty,SqlSessionFacoty 一旦创建完成就不需要SqlSessionFactoryBuilder 了,因为 SqlSession 是通过 SqlSessionFactory 生产,所以可以将SqlSessionFactoryBuilder 当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
2、SqlSessionFactory
SqlSessionFactory 是一个接口,接口中定义了 openSession 的不同重载方法,SqlSessionFactory 的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理 SqlSessionFactory。
3、SqlSession
SqlSession 是一个面向用户的接口, sqlSession 中定义了数据库操作,默认使用 DefaultSqlSession 实现类。
使用DAO实现类的方式操作数据库-构造器注入
创建DAO
package com.foreknow.dao;
import java.sql.SQLException;
import java.util.List;
import com.foreknow.bean.User;
public interface UserDao {
/**
* 根据id查询用户信息
* @param id
* @return User
* @throws SQLException
*/
public User findUserById(int id)throws SQLException;
/**
* 模糊查询用户信息列表
* @param name
* @return List<User>
* @throws SQLException
*/
public List<User> findUserByName(String name)throws SQLException;
/**
* 添加用户信息
* @param user
* @throws SQLException
*/
public void insertUser(User user)throws SQLException;
/**
* 根据id删除用户信息
* @param id
* @throws SQLException
*/
public void deleteUser(int id)throws SQLException;
/**
* 修改用户信息
* @param user
* @throws SQLException
*/
public void updateUser(User user)throws SQLException;
}
创建DAO实现类
package com.foreknow.dao;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.foreknow.bean.User;
public class UserDaoImpl implements UserDao {
// 需要向dao实现类中注入SqlSessionFactory
// 这里通过构造方法注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", id);
// 释放资源
sqlSession.close();
return user;
}
@Override
public List<User> findUserByName(String name) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("test.findUserByName", name);
// 释放资源
sqlSession.close();
return list;
}
@Override
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行插入操作
sqlSession.insert("test.insertUser", user);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
@Override
public void deleteUser(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行插入操作
sqlSession.delete("test.deleteUser", id);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
}
创建JUnit测试类
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
// 此方法是在执行testFindUserById之前执行
@Before
public void setUp() throws Exception {
// 创建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
// 创建UserDao的对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
// 调用UserDao的方法
User user = userDao.findUserById(1);
System.out.println(user);
}
}
自定义别名:
在 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>
<!-- 加载属性文件 -->
<properties resource="db.properties">
</properties>
<!-- 全局配置参数,需要时再设置 -->
<!-- <settings>
</settings> -->
<!--起别名 -->
<typeAliases>
<!-- <typeAlias type="com.neusoft.mybatis.pojo.User" alias="User"/> -->
</typeAliases>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis-->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理-->
<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>
<!-- 加载 映射文件 -->
<mappers>
<mapper resource="mapper/User.xml" />
<!-- <mapper resource="mapper/UserMapper.xml" /> -->
</mappers>
</configuration>
Mybatis 的 mapper 接口
程序员需要编写mapper接口(相当于Dao接口,增删改查操作)
程序员需要编写 mapper.xml 映射文件,需遵循一些开发规范,mybatis 可以自动生成 mapper 接口类代理对象。
开发规范:
1.在 mapper.xml 中 namespace 等于 mapper 接口地址(所在包名的全路径)
<mapper namespace="com.mapper.UserMapper"></mapper>
2.在 xxxmapper.java 接口中的方法名要与 xxxMapper.xml 中 statement 的 id 一致。
3.在 xxxmapper.java 接口中的输入参数类型要与 xxxMapper.xml 中 statement 的 parameterType 指定的参数类型一致。
4.在 xxxmapper.java 接口中的返回值类型要与 xxxMapper.xml 中 statement 的 resultType 指定的类型一致。
5.接口文件名要与xml映射文件名一致(UserMapper.java和UserMapper.xml)
根据用户 id(主键)查询用户信息
定义Mapper接口
public interface UserMapper {
public User findUserById(int id);
}
定义UserMapper.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="com.foreknow.dao.UserMapper">
<select id="findUserById" parameterType="int" resultType="com.foreknow.bean.User">
select * from user where id = #{value}
</select>
</mapper>
主方法测试
public static void main(String[] args) throws IOException {
//创建sqlSessionFactory
//Mybatis 配置文件
String resource = "SqlMapConfig.xml";
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入Mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建usermapper对象,mybatis自动生成代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper的方法
User user = userMapper.findUserById(1);
System.out.println(user.getUsername());
}
最后 如果关联绑定的mapper.xml文件 也得在SqlMapConfig.xml 的核心文件中
加载映射文件
<!-- 加载 映射文件 -->
<mappers>
<mapper resource="mapper/User.xml" />
<mapper resource="mapper/UserMapper.xml" />
</mappers>