mybatis入门之增删改查
一、原生态JDBC程序中问题的总结
1.1 JDBC程序
需求:使用jdbc查询mysql数据库中用户的记录
Statement:向数据库发送回个sql语句
预编译Statement: 好处:提高数据库性能
预编译Statement向数据库发送一个sql语句,数据库执行后将执行结果存放在缓存中,下次再执行相同的语句会直接从缓存中读取
1、 加载数据库驱动
2、 创建并获取数据库链接
3、 创建jdbc statement对象
4、 设置sql语句
5、 设置sql语句中的参数(使用preparedStatement)
6、 通过statement执行sql并获取结果
7、 对sql执行结果进行解析处理
8、 释放资源(resultSet、preparedstatement、connection)
public class JDBCTest {
public static void main(String[] args) {
Connection connection = null;
// 预编译的Statement,使用预编译的Statement提高数据库性能
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过驱动管理类获取数据库链接
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test?characterEncoding=utf-8",
"root", "root");
// 定义sql语句 ?表示占位符
String sql = "select * from t_user where username = ?";
//获取预处理statement
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
// 向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
// 遍历查询结果集
while (resultSet.next()) {
System.out.println(resultSet.getString("id") + " "+ resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
1.2问题总结:
上面代码的问题总结
1、数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。
设想:使用数据库连接池管理数据库连接。
2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。
3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
设想:将sql语句及占位符号和参数全部配置在xml中。
4、从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,,不利于系统维护。
设想:将查询的结果集,自动映射成java对象。
二、mybatis原理
2.1 mybatis是什么?
mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis托管到goolecode下,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)。
mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)
2.2 mybatis框架
aaa.png1、 mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
三、入门程序之mybatis增删改查
3.1 需求
根据用户id(主键)查询用户信息
根据用户名称模糊查询用户信息
添加用户
删除 用户
更新用户
3.2 PC环境
java环境:1.7.0_40
eclipse
mysql: 5.7
3.3 创建mysql数据库
新建数据库mybatis,新建表user
user详细信息
3.4所需Jar包
MyBatis下载地址:https://github.com/mybatis/mybatis-3/releases
mybatis-3.4.4.jar :核心包
mysql-connector-java-5.1.jar:mysql的驱动包
3.4 工程结构
在eclipse中新建java工程,创建下面的工程结构,并把jar把添加到lib中
ccc.png
3.5 配置log4j.properties
开发环境 下日志级别设置为DEBUG, log4j.rootLogger=DEBUG, stdout; 生产环境设置为info或error
# 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
3.6 配置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中还可以配置一些属性名和属性值 -->
<!-- <property name="jdbc.driver" value=""/> -->
</properties>
<!-- 全局配置参数,需要时再设置 -->
<!-- <settings>
</settings> -->
<!-- 别名定义 -->
<typeAliases>
<!-- 针对单个别名定义
type:类型的路径
alias:别名
-->
<!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
<!-- 批量别名定义
指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以)
-->
<package name="cn.itcast.mybatis.po"/>
</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="sqlmap/User.xml"/>
</mappers>
</configuration>
3.7 根据用户id(主键)查询用户信息
3.7.1 创建po类
在cn.eugene.po下创建user类
package cn.eugene.po;
public class User {
private int id;
private String userName;
private String userAge;
private String userAddress;
public User() {
super();
// TODO Auto-generated constructor stub
}
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* @return the userAge
*/
public String getUserAge() {
return userAge;
}
/**
* @param userAge the userAge to set
*/
public void setUserAge(String userAge) {
this.userAge = userAge;
}
/**
* @return the userAddress
*/
public String getUserAddress() {
return userAddress;
}
/**
* @param userAddress the userAddress to set
*/
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", userAge=" + userAge + ", userAddress=" + userAddress
+ "]";
}
}
3.7.2 映射文件
在项目目录的sqlmap下创建user的映射文件userMapp.xml,并配置根据id查询用的sql语句
<?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">
<!-- 根据id查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="cn.eugene.po.User">
select * from user where id = #{id}
</select>
</mapper>
3.7.3 在SqlMapConfig.xml加载映射文件
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
3.7.4 编写测试程序,根据id查询用户信息
package cn.eugene.first;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Test;
import cn.eugene.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisFirst {
@Test
public void findUserByIdTest() throws IOException{
//得到配置文件流
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通过会话工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", "1");
System.out.println(user);
sqlSession.close();
}
@Test
public void deleteUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通过会话工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", "2");
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通过会话工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(2);
user.setUserName("出运费");
user.setUserAge("21");
user.setUserAddress("重庆");
sqlSession.update("test.updateUser", user);
sqlSession.commit();
sqlSession.close();
}
}
3.8 添加用户
sql配置
<insert id="insertUser" parameterType="cn.eugene.po.User">
insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress})
</insert>
测试方法
@Test
public void insertUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通过会话工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUserName("出运费");
user.setUserAge("21");
user.setUserAddress("重庆2");
sqlSession.update("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
}
3.9 删除用户更新用户
sql配置
<!-- 根据id删除用户 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="cn.eugene.po.User">
update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id= #{id}
</update>
测试方法
@Test
public void insertUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通过会话工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUserName("出运费");
user.setUserAge("21");
user.setUserAddress("重庆2");
sqlSession.update("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
}
3.10添加用户主键返回
<insert id="insertUser2" parameterType="com.ganlion.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress})
</insert>
测试方法
@Test
public void insertUser2(){
InputStream inputstream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通过会话工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUserName("飛天");
user.setUserAge("24");
user.setUserAddress("上海浦江");
session.insert("test.insertUser2", user);
session.commit();
System.out.println("返回的插入的主鍵id:"+user.getId());
session.close();
}
四、总结
sql配置文件中
parameterType指定输入参数类型
resultType指定输出参数类型
#{}表示一个占位符,#{}接收输入参数。#{}可以有效防止sql注入。类型可以是简单类型,pojo、hashmap。如果接收简单类型,#{}中可以写成value或其它名称。
#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。
${}表示一个拼接符号,拼接sql串,会引起sql 注入存在安全隐患,所以不建议使用${}。${}接收输入参数,类型可以是简单类型,pojo、hashmap。如果接收简单类型,${}中只能写成value。
${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。
五、编写入门程序可能遇到的问题
问题一、Could not find resource SqlMapConfig.xml
ddd.png原因:一开始是因为默认的情况下,只有src是build path的source folder目录,自定义的文件夹在Use as Source Folder前只是一个普通的文件夹,默认的情况下不会被加载,需要手动将自定义的文件夹加载为source folder。也就是之前所说的步骤。
解决办法:右键点击SqlMapConfig.xml所在的文件夹(我的是config)------>Build Path------>Use as Source Folder
参考mybatis中遇到Could not find resource SqlMapConfig.xml
问题二、当查询数据库数据的时候,控制台System.out.println(user)输出了NULL
注意sql配置文件查询的字段和数据库对应