一、概念
简单的说:一款封装了数据库JDBC操作的ORM框架技术.(Apache(ibatis) --> Google(Mybatis))
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
ORM:Object Relation Mapping对象关系映射
ORM设计思想:将数据库中的一张表与java实体类关联起来,表中每一行记录映射成实体类对象,可以通过映射关系将实体类中数据存储到数据库中,也可以将数据库中一行记录映射成一个java实体类对象。ORM是一种设计思想,Hibernate和Mybatis都是实现了这种思想的框架。其中ORM映射分为四级:第一级别为手动连接的SQLutils.第二级别为半自动化的MyBatis框架.第四级便是持久性框架Hibernate,这个在之前的博客有详解.这里我们来详细学习一下MyBatis框架操作实体类数据库.
二、MyBatis框架的优缺点
优点:
1.基于SQL语句的框架,可以实现对SQL语句的调优。
2.将SQL语句单独编写在xml配置文件中,方便统一管理和维护,降低程序之间的耦合度。
3.提供xml标签,支持动态SQL语句编写。
4.提供xml映射标签,支持表与表之间的关联查询。
缺点:
1.需要自己编写SQL语句,对开发人员的能力有要求。
2.数据库移植能力较差。
3.不支持表与表之间级联增删改。
三、MyBatis的使用步骤
1.创建数据库
#创建数据库
create database mybatis default character set utf8;
#使用数据库
use mybatis;
#创建表
create table user(
id int primary key auto_increment,
username varchar(20),
password varchar(20),
age int,
gender char(1));
#插入数据
INSERT INTO user (username,password,age,gender) values
("张三","123",20,'男'),("李四","123",21,'男'),("王五","123",23,'男'),("赵六","123",24,'男');
2.创建项目,导入核心Jar包
mybatis-3.4.5.jar 是mybatis核心API
mysql.jar 是数据库操作Jar
3.编写Mybatis主配置文件:SqlMapConfig.xml
主要编写数据库连接参数信息和其他配置.
<configuration>
<!-- 引用Properties配置文件的 -->
<properties resource="jdbc.properties">
</properties>
<!-- 全局系统设置:使用log4j框架打印Sql语句 -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
<!-- 开启二级缓存..延迟加载之类的. -->
</settings>
<!-- 给实体类类型起别名,方便在sql映射文件中使用 -->
<typeAliases>
<typeAlias type="com.hekaikai666.bean.User" alias="user" />
<typeAlias type="com.hekaikai666.bean.Emp" alias="emp" />
</typeAliases>
<!-- 资源 -->
<environments default="environment">
<environment id="environment">
<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>
<!-- 关联SQL映射文件 -->
<mappers>
<mapper resource="com/hekaikai666/dao/i/UserMapper.xml" />
</mappers>
</configuration>
4.根据表编写实体类.建议:实体类中属性名和表中字段名保持一致.(如果不一致请参考User1)
package com.hekaikai666.bean;
import java.io.Serializable;
/**
*
* @author hekaikai666
* @time 2018年9月17日上午11:24:57
**/
public class User implements Serializable {
private int id;
private String username;
private String password;
private int age;
private String gender;
// 此处省略空参构造方法,不包含id的全参构造方法,全参构造方法,get set方法和toString方法
}
package com.hekaikai666.bean;
import java.io.Serializable;
/**
*
* @author hekaikai666
* @time 2018年9月17日下午4:49:40
**/
public class User1 implements Serializable {
private int u_id;
private String u_username;
private String u_password;
private int u_age;
private String u_gender;
// 此处省略 空参构造方法,不包含id的全参构造方法,全参构造方法,以及get set方法和toString方法
}
5.编写SQL映射文件,主要编写SQL语句,让主配置文件关联加载映射文件
<!-- SQL映射文件:多个SQL映射文件之间,namespace不能相同 -->
<mapper namespace="user">
<!-- 作用:提取多个SQL定义中相同的SQL片段 -->
<sql id="selectAll">SELECT * FROM user</sql>
<!-- 根据id查询一个User对象
id:代表当前这个SQL定义 #{id}:代表占位符,大括号中的id和属性名一致
parameterType:传给占位符的参数类型
resultType:SQL语句执行完成后的返回结果
include:对相同Sql语句片段的提取 -->
<!-- 执行查找对象的两种方式哦 -->
<select id="findUserById" parameterType="int" resultType="user">SELECT
* FROM user WHERE id=#{id}</select>
<select id="findUserById" parameterType="int" resultType="user">
<include refid="selectAll" />
WHERE id=#{id}
</select>
<!-- 查询所有User数据 返回list集合时,resultType写集合元素类型,mybatis会自动将其封装为集合 -->
<!-- <select id="findAll" resultType="user">SELECT * FROM user</select> -->
<select id="findAll" resultType="user">
<include refid="selectAll" />
</select>
<!-- 插入一条数据 -->
<insert id="saveUser" parameterType="user">INSERT INTO user
(username,password,age,gender) VALUES
(#{username},#{password},#{age},#{gender})
</insert>
<!-- 删除一条数据 -->
<delete id="deleteUserById" parameterType="int">DELETE FROM user WHERE id=#{id}</delete>
<!-- 根据id修改一行记录 -->
<update id="updateUser" parameterType="user">UPDATE user SET username=#{username},password=#{password},age=#{age},gender=#{gender} WHERE id=#{id}</update>
<!-- 根据名字进行模糊查询 -->
<select id="findThem" parameterType="java.lang.String" resultType="user"><include refid="selectAll"/>WHERE username like #{username}</select>
<!-- 根据账号密码查询一个账户:user对象传入 -->
<select id="findOneByUAP" parameterType="user" resultType="user"><include refid="selectAll"/>WHERE username=#{username} and password=#{password}</select>
<!-- 根据账号密码查询一个账户:map对象传入 -->
<select id="findOneByUAP2" parameterType="map" resultType="user"><include refid="selectAll"/>WHERE username=#{username} and password=#{password}</select>
<!-- 根据id只查询账号和密码 -->
<select id="findOneById" parameterType="int" resultType="java.lang.String">SELECT username,password FROM user WHERE id=#{id}</select>
<!-- 查询所有用户的账号和密码 -->
<select id="findAllUAP" resultType="java.lang.String">SELECT username,password FROM user</select>
<!-- 分页查询所有用户的信息 -->
<select id="getUserByLimit" parameterType="map" resultType="user">SELECT * FROM user LIMIT #{page},#{pageSize}</select>
<!-- 查询表中所有数据并封装成user1类型对象集合 -->
<!-- 方案一:给列起别名,别名的名字和实体类属性名相同 -->
<select id="findAllUser1" resultType="com.hekaikai666.bean.User1">
SELECT
id u_id,
username u_username,
password u_password,
age u_age,
gender u_gender
FROM user
</select>
<!-- 方案二:借助resultType标签做实体类中属性名和表中字段之间映射关系 -->
<!-- type:表中每一行记录封装成什么类型对象 id:当前resultMap映射结果id -->
<resultMap type="com.hekaikai666.bean.User1" id="user1Bean">
<!-- 主键映射:property:实体类中属性名称 column:表中字段名称 -->
<id property="u_id" column="id"/>
<!-- 非主键映射: -->
<result property="u_username" column="username"/>
<result property="u_password" column="password"/>
<result property="u_age" column="age"/>
<result property="u_gender" column="gender"/>
</resultMap>
<!-- 查询所有数据封装成User1对象类型集合 -->
<select id="findUser1" resultMap="user1Bean">SELECT * FROM user</select>
</mapper>
6.通过mybatis中的API获取到SqlSession对象.
获取sessionFactory对象可以封装为util方法,无需重复写
// 获取sessionFactory对象
public static SqlSessionFactory getFactory() {
// 获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 加载mybatis配置文件
// 通过类加载器对象来加载文件获取一个流
String resource = "SqlMapConfig.xml";
InputStream is = TestUser.class.getClassLoader().getResourceAsStream(resource);
// 使用session工厂对象加载文件(每个应用程序能够对应一个SqlSessionFactory)
// 可以用于构建你SqlSession对象和充当二级缓存
SqlSessionFactory factory = builder.build(is);
return factory;
}
User对象和User1对象的十三种基本增删改查操作.
* 查找单个User对象
* 查找所有User对象并风格到List集合中
* 给输入库中添加一个User对象
* 根据id删除一个User对象
* 根据id修改一个对象
* 根据名字进行模糊查询
* 根据账号密码查询一个账户
* 根据id只查询账号和密码
* 查询所有用户的账号和密码
* 当实体类中属性名和表中字段名不一致时查询
* 根据账号和密码查询一个用户的 信息进行登录 如果能查到 成功 如果查不到 失败 模拟JdbcSQL注入
* mybatis分页查询
* 根据名字查找一个User对象
* 根据账号和密码进行查询
* 传入数据表名进行查询
package com.hekaikai666.Test;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Before;
import org.junit.Test;
import com.hekaikai666.bean.User;
import com.hekaikai666.bean.User1;
import com.hekaikai666.util.MyBatisUtil;
import jdk.nashorn.internal.ir.ForNode;
/**
*
* @author hekaikai666
* @time 2018年9月17日上午11:42:16
**/
public class TestUser {
SqlSessionFactory factory;
@Before
public void init() {
factory = MyBatisUtil.getFactory();
}
/**
* 查找单个User对象
*
* @throws FileNotFoundException
*/
@Test
public void test1() {
// 使用session工厂打开session
SqlSession session = factory.openSession();
// 通过session对象执行映射文件中的SQL语句
String statement = "findUserById";
// 第一个参数 Sql定义的id 第二个参数 占位符的参数值
// 1.查询SQL语句
User user = session.selectOne(statement, 1);
System.out.println(user);
session.close();
}
/**
* 查找所有User对象并风格到List集合中
*/
@Test
public void test2() {
SqlSession session = factory.openSession();
// 如果多个映射文件有相同的sql定义id可以使用namespace.id名来
List<User> users = session.selectList("user.findAll");
for (User user : users) {
System.out.println(user);
}
session.close();
}
/**
* 给输入库中添加一个User对象
*/
@Test
public void test3() {
SqlSession session = factory.openSession();
User user = new User("宋豪", "123456", 80, "男");
int rows = session.insert("saveUser", user);
// 提交事务
session.commit();
System.out.println("成功插入数据的行数:" + rows);
// 关闭对象
session.close();
}
/**
* 根据id删除一个User对象
*/
@Test
public void test4() {
SqlSession session = factory.openSession();
int rows = session.delete("user.deleteUserById", 6);
System.out.println("删除记录行数:" + rows);
session.commit();
session.close();
}
/**
* 根据id修改一个对象
*/
@Test
public void test5() {
SqlSession session = factory.openSession();
// 先根据id获取一个user对象
User user = session.selectOne("findUserById", 3);
user.setUsername("哈哈哈");
user.setPassword("呵呵呵");
user.setAge(18);
user.setGender("女");
int rows = session.update("user.updateUser", user);
System.out.println("修改记录行数:" + rows);
session.commit();
session.close();
}
/**
* 根据名字进行模糊查询
*/
@Test
public void test6() {
SqlSession session = factory.openSession();
List<User> users = session.selectList("findThem", "%张%");
for (User user : users) {
System.out.println(user);
}
session.close();
}
/**
* 根据账号密码查询一个账户
*/
@Test
public void test7() {
SqlSession session = factory.openSession();
// 传入一个User对象
User user = new User("张三", "123", 0, "");
List<User> u = session.selectList("findOneByUAP", user);
System.out.println(u);
session.close();
// 传入一个map集合
Map<String, String> map = new HashMap<String, String>();
map.put("username", "张三");
map.put("password", "123");
User user1 = session.selectOne("findOneByUAP2", map);
System.out.println(user1);
session.close();
}
/**
* 根据id只查询账号和密码
*/
@Test
public void test8() {
SqlSession session = factory.openSession();
List<Map<String, String>> user = session.selectList("findOneById", 1);
for (Map<String, String> map : user) {
System.out.println(map);
}
session.close();
}
/**
* 查询所有用户的账号和密码
*/
@Test
public void test9() {
SqlSession session = factory.openSession();
List<Map<String, String>> users = session.selectList("findAllUAP");
for (Map<String, String> map : users) {
System.out.println(map);
}
session.close();
}
/*
* 当实体类中属性名和表中字段名不一致时查询
*/
@Test
public void test01() {
SqlSession session = factory.openSession();
List<User1> user1s = session.selectList("findUser1");
for (User1 user1 : user1s) {
System.out.println(user1);
}
}
/**
* 根据账号和密码查询一个用户的 信息进行登录 如果能查到 成功 如果查不到 失败 模拟JdbcSQL注入
*
* @throws ClassNotFoundException
* @throws SQLException
*/
@Test
public void testJDBC() throws ClassNotFoundException, SQLException {
String username="宋豪";
String password="1234' or '1=1";
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8",
"root", "123456");
String sql = "SELECT * FROM user WHERE username='"+username+"' and password='"+password+"';";
Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
// ResultSet rs = stmt.executeQuery(sql);
if (rs.next()) {
System.out.println("登陆成功");
} else {
System.out.println("登陆失败");
}
}
/**
* mybatis分页查询
*/
@Test
public void test10() {
SqlSession session = factory.openSession();
HashMap<String, Object> maps = new LinkedHashMap<String,Object>();
maps.put("page", 2);
maps.put("pageSize", 3);
List<User> lists = session.selectList("user.getUserByLimit", maps);
for (User user : lists) {
System.out.println(user);
}
}
/**
* 根据名字查找一个User对象
*/
@Test
public void test11() {
SqlSession session = factory.openSession();
User user = session.selectOne("u.findUserByName","'张三'");
System.out.println(user);
session.close();
}
/**
* 根据账号和密码进行查询
*/
@Test
public void test12() {
SqlSession session = factory.openSession();
HashMap<String, Object> map = new HashMap<String,Object>();
map.put("username", "'张三'");
map.put("password", "'12345' or '1=1'");
User user = session.selectOne("u.findUserByNameAndPsw",map);
System.out.println(user);
session.close();
}
/**
* 传入数据表名进行查询
*/
@Test
public void test13() {
SqlSession session = factory.openSession();
String table = "user";
User user = session.selectOne("u.findAll",table);
System.out.println(user);
session.close();
}
}