MyBatis01
MyBatis01
1. JDBC編程問題總結
1.1 數據準備
/*
Navicat MySQL Data Transfer
Source Server : localhost_3306
Source Server Version : 50521
Source Host : localhost:3306
Source Database : mybatis
Target Server Type : MYSQL
Target Server Version : 50521
File Encoding : 65001
Date: 2015-04-09 16:03:53
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `orders`
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下單用戶id',
`number` varchar(32) NOT NULL COMMENT '訂單號',
`createtime` datetime NOT NULL COMMENT '創建訂單時間',
`note` varchar(100) DEFAULT NULL COMMENT '備注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null);
INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null);
INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null);
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
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=27 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
INSERT INTO `user` VALUES ('10', '張三', '2014-07-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);
1.2 創建工程
說明:
- 簡單Java項目即可
- 可以使用Maven或者Jar的方式添加驅動
代碼:
package com.lanou3g;
import java.sql.*;
public class Main {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 加載數據庫驅動
Class.forName("com.mysql.cj.jdbc.Driver");
// 通過驅動管理類獲取數據庫鏈接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&characterEncoding=utf-8", "root", "123456");
// 定義sql語句 ?表示占位符
String sql = "select * from 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.3 JDBC問題總結
- 數據庫連接創建、釋放頻繁造成系統資源浪費,從而影響系統性能。如果使用數據庫連接池可解決此問題。
- Sql語句在代碼中硬編碼,造成代碼不易維護,實際應用中sql變化的可能較大,sql變動需要改變java代碼
- 使用preparedStatement向占有位符號傳參數存在硬編碼,因為sql語句的where條件不一定,可能多也可能少,修改sql還要修改代碼,系統不易維護
- 對結果集解析存在硬編碼(查詢列名),sql變化導致解析代碼變化,系統不易維護,如果能將數據庫記錄封裝成pojo對象解析比較方便
2. MyBatis架構
2.1 說明
- mybatis配置
- SqlMapConfig.xml: 此文件作為mybatis的全局配置文件,配置了mybatis的運行環境等信息
- mapper.xml: 即sql映射文件,文件中配置了操作數據庫的sql語句。此文件需要在SqlMapConfig.xml中加載,通常一個表對應一個mapper.xml
- 通過mybatis環境等配置信息構造SqlSessionFactory即會話工廠
- 由會話工廠創建sqlSession即會話,操作數據庫需要通過sqlSession進行
- mybatis底層自定義了Executor執行器接口操作數據庫,Executor接口有兩個實現,一個是基本執行器、一個是緩存執行器
- Mapped Statement也是mybatis一個底層封裝對象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個sql對應一個Mapped Statement對象,sql的id即是Mapped statement的id
- Mapped Statement對sql執行輸入參數進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行sql前將輸入的java對象映射至sql中,輸入參數映射就是jdbc編程中對preparedStatement設置參數
- Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行sql后將輸出結果映射至java對象中,輸出結果映射過程相當于jdbc編程中對結果的解析處理過程
3. Mybatis入門程序
根據用戶ID查詢一個用戶
3.1 mybatis下載
mybatis的代碼由github托管,下載地址:https://github.com/mybatis/mybatis-3/releases
3.2 添加依賴
3.3 POJO
User:
package com.lanou3g.pojo;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String username;// 用戶姓名
private String sex;// 性別
private Date birthday;// 生日
private String address;// 地址
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
}
Orders
package com.lanou3g.pojo;
import java.io.Serializable;
import java.util.Date;
public class Orders implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private Integer userId;
private String number;
private Date createTime;
private String note;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number == null ? null : number.trim();
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note == null ? null : note.trim();
}
}
3.4 配置文件
mybatis核心配置文件
在src下創建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>
<environments default="development">
<environment id="development">
<!--使用JDBC事務管理-->
<transactionManager type="JDBC"/>
<!--數據庫連接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--mapper文件的位置-->
<mappers>
<mapper resource="com/lanou3g/sqlmap/User.xml"/>
</mappers>
</configuration>
log
在src下創建log4j.properties
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
說明:
- 不適用log4j 不會影響mybatis的使用
mapper映射文件
在sqlmap包下創建User的映射文件 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">
<!--寫SQL語句
命名空間: user.findUserById-->
<mapper namespace="user">
<!--通過ID查詢一個用戶-->
<select id="findUserById" parameterType="Integer" resultType="com.lanou3g.pojo.User">
SELECT * FROM USER WHERE id = #{v}
</select>
</mapper>
說明:
- 在mybatis中使用 #{v}
來作為占位符(?
)拼接sql語句
- id: statement的id或者叫做 sql 的id
- parameterType: 聲明輸入參數的類型
- resultType: 聲明輸出結果的類型,應該填寫pojo的全路徑
3.5 測試運行
使用Junit來進行測試,編寫測試程序的步驟:
1. 加載sqlMapConfig.xml配置文件
2. 通過SqlSessionFactoryBuilder創建SqlSessionFactory對象
3. 創建SqlSession對象
4. 使用SqlSession對象執行在mapper中編寫的sql語句獲得返回值
5. 打印結果
6. 釋放資源
package com.lanou3g.junit;
import com.lanou3g.pojo.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;
import org.junit.Test;
import java.io.InputStream;
public class MybatisFirstTest {
@Test
public void testMybatis() throws Exception{
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.findUserById", 10);
System.out.println(user);
in.close();
sqlSession.close();
}
}
3.5 說明
sqlMapConfig.xml,User.xml和MybatisFirstTest.java之間的對應關系如圖所示:
- 在sqlMapConfig.xml的mappers標簽中將所有的map.xml進行注冊,需要制定xml文件的位置
- 在Java中使用Resource.getResourceAsXXX來加載配置sqlMapConfig.xml,可以有很多的返回值,這個返回值需要和SqlSessionFactoryBuilder.build()方法中的參數對應上
- 在查找一條數據時使用
selectOne
方法,第一個參數是mapper中sql語句的id,這個id是mapper的namespace.id
3.6 增刪改查入門
業務需求:
- 根據用戶名模糊查詢用戶列表
- 添加用戶
- 更新用戶
- 刪除用戶
1. 模糊查詢
映射
<select id="findUserByUserName" parameterType="String" resultType="com.lanou3g.pojo.User">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
測試代碼:
@Test
public void testFindUserByName() throws Exception {
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(in);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users =
sqlSession.selectList("user.findUserByUserName", "五");
for (User user : users) {
System.out.println(user);
}
in.close();
sqlSession.close();
}
效果:
說明
#{}
和${}
#{}
- #{}
表示一個占位符,通過#{}
可以實現 perparedStatement 向占位符中設置值, 自動進行java類型和jdbc類型轉換
- #{}
可以有效防止sql注入
- #{}
可以接受簡單類型值或pojo屬性值
- 如果parameterType傳輸單個簡單類型值,#{}
括號中可以是value或其他名稱
${}
- ${}
表示拼接sql字符串,通過${}
可以將parameterType傳入的內容拼接在sql中且不進行jdbc類型轉換
- ${}
可以接收簡單類型值或pojo屬性值
- ${}
不能防止sql注入
- 如果parameterType傳輸單個簡單類型值,${}
括號中只能是value
mapper還可以寫成:
<select id="findUserByUserName" parameterType="String" resultType="com.lanou3g.pojo.User">
SELECT * FROM USER WHERE username LIKE "%"#{value}"%"
</select>
運行結果:
parameterType和resultType
- parameterType:指定輸入參數類型,mybatis通過ognl從輸入對象中獲取參數值拼接在sql中
- resultType:指定輸出結果類型,mybatis將sql查詢結果的一行記錄數據映射為resultType指定類型的對象。如果有多條數據,則分別進行映射,并把對象放到容器List中
selectOne和selectList
- selectOne: 查詢一條記錄,如果使用selectOne查詢多條記錄則拋出異常
- selectList: 可以查詢一條或多條記錄
2. 添加用戶
映射文件:
<insert id="saveUser" parameterType="com.lanou3g.pojo.User">
INSERT INTO `user`
(username,birthday,sex,address) VALUES
(#{username},#{birthday},#{sex},#{address})
</insert>
java代碼:
@Test
public void testSaveUser() throws Exception {
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(in);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUsername("張飛");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("蜀國");
sqlSession.insert("user.saveUser", user);
System.out.println(user);
in.close();
sqlSession.close();
}
運行效果
存在問題:
當保存完成后User的id并沒有跟數據庫中的值保持一致
mysql自增主鍵返回
在mysql中有:
SELECT LAST_INSERT_ID()
可以返回上一次增加的主鍵值,修改配置文件:
<insert id="saveUser" parameterType="com.lanou3g.pojo.User">
<selectKey keyColumn="id" keyProperty="id" order="AFTER"
resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO `user`
(username,birthday,sex,address) VALUES
(#{username},#{birthday},#{sex},#{address})
</insert>
說明:
- selectKey: 標簽實現主鍵返回
- keyColumn: 主鍵對應的表中的哪一列
- keyProperty: 主鍵對應的pojo中的哪一個屬性
- order: 設置在執行insert語句前執行查詢id的sql,還是在執行insert語句之后執行查詢id的sql
- resultType: 設置返回的id的類型
運行結果
3. 修改用戶
映射文件
<update id="updateUserById" parameterType="com.lanou3g.pojo.User">
UPDATE `user` SET
username = #{username} WHERE id = #{id}
</update>
測試代碼
@Test
public void testUpdateUser() throws Exception {
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(in);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(26); // 設置id
user.setUsername("關羽");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("蜀國");
sqlSession.update("user.updateUserById", user);
System.out.println(user);
sqlSession.commit();
in.close();
sqlSession.close();
}
運行結果:
4. 刪除用戶
配置文件:
<delete id="deleteById" parameterType="Integer">
DELETE FROM USER WHERE id = #{VALUE}
</delete>
測試代碼:
@Test
public void testDelById() throws Exception{
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(in);
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("user.deleteById", 26);
sqlSession.commit();
in.close();
sqlSession.close();
}
運行效果:
智能推薦
【Mybatis01】實現縮小版銀行轉賬+分頁查詢功能
一、實現轉賬 1.1 項目實現圖和結構圖 1.1.1 pojo實體類 !分頁查詢表 1.2 全局文件mybatis.xml的編寫 1.3 mapper.xml的編寫(用來進行查詢!!!) 1.3.1分析: (確保轉賬用戶的正確性)因為需要確認轉賬用戶的賬號密碼輸入正確,所以需要根據賬號和密碼進行表查詢并且拿出查出來的對象,以作后續的余額更改操作! (確保入帳用戶的正確性)同上述,查表,取出對象! ...
MyBatis(01)
攔截器和過濾器的區別 1.攔截器是SpringMvc框架的組件,而過濾器是java提供的API 2.攔截器只能攔截目標為DispatcherServlet的請求 過濾器范圍廣,過濾目標可以是任何資源 3.功能上攔截器功能更強,和SpringMvc配合更方便 過濾器只和javaEEAPI相關,功能稍弱 小結 如果實現http協議級別的基本攔截過濾,就使用過濾器 如果實現對SpringMvc控制器代碼...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
猜你喜歡
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...