第一次在WPF项目里用MySQL时,我对着满屏的配置参数差点崩溃。后来发现只要按步骤操作,其实比SQL Server还简单。咱们先从最基础的MySQL安装开始,我会把每个细节都掰开讲清楚。
去MySQL官网下载Community Server版本时,建议选择8.0以上的稳定版。下载完成后别急着安装,先在解压目录(比如D:\mysql-8.0.34-winx64)新建个my.ini配置文件。这个文件相当于MySQL的"使用说明书",我常用的配置模板是这样的:
ini复制[mysqld]
port=3306
basedir=D:/mysql-8.0.34-winx64
datadir=D:/mysql-8.0.34-winx64/data
max_connections=200
default-storage-engine=INNODB
character-set-server=utf8mb4
[client]
default-character-set=utf8mb4
这里有个坑我踩过三次:datadir指定的data文件夹千万不要手动创建,让MySQL自己初始化生成。用管理员权限打开CMD,进入bin目录执行mysqld --initialize --console,这时控制台会打印出临时密码,记得拍照保存。接着用mysqld --install注册服务,net start mysql启动服务后,马上用mysql -uroot -p登录修改密码:
sql复制ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';
最后别忘了配置环境变量,把MySQL的bin目录(比如D:\mysql-8.0.34-winx64\bin)加到系统PATH里。验证安装是否成功,直接在任意位置打开CMD输入mysql -V能显示版本号就对了。
Visual Studio这边我用的是2022社区版,新建WPF项目时要注意.NET版本选择。个人推荐用.NET Core 3.1或.NET 5+,它们对MySQL的支持更完善。项目创建完成后,第一件事就是通过NuGet安装MySql.Data包,这是官方提供的连接器。
在包管理器控制台输入:
powershell复制Install-Package MySql.Data -Version 8.0.33
安装时可能会遇到依赖冲突,特别是项目里如果用了其他数据库组件。我常用的解决办法是先用Update-Package -reinstall重置依赖,再单独安装MySQL组件。装完后检查References里是否有MySql.Data.dll,有的话就可以开始写连接代码了。
先设计个简单的登录界面:两个TextBox输入用户名密码,一个Button触发连接,再加个TextBlock显示状态。核心代码其实就三部分:
csharp复制private void ConnectButton_Click(object sender, RoutedEventArgs e)
{
string connStr = "server=localhost;user=root;database=test;port=3306;password=你的密码";
using (MySqlConnection conn = new MySqlConnection(connStr))
{
try
{
conn.Open();
StatusText.Text = "连接成功!服务器版本:" + conn.ServerVersion;
// 示例查询
string sql = "SELECT COUNT(*) FROM users";
MySqlCommand cmd = new MySqlCommand(sql, conn);
int count = Convert.ToInt32(cmd.ExecuteScalar());
MessageBox.Show($"用户表中共有{count}条记录");
}
catch (Exception ex)
{
StatusText.Text = "连接失败:" + ex.Message;
}
}
}
这里有几个优化点:
我推荐用ConfigurationBuilder来管理连接字符串:
csharp复制var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
string connStr = builder.Build().GetConnectionString("MySQL");
基础连接跑通后,咱们来实现些实用功能。比如带参数化查询的用户登录验证:
csharp复制public bool ValidateLogin(string username, string password)
{
string sql = "SELECT COUNT(*) FROM users WHERE username=@name AND password=@pwd";
using (var conn = new MySqlConnection(connStr))
{
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@name", username);
cmd.Parameters.AddWithValue("@pwd", ComputeMd5Hash(password));
conn.Open();
int count = Convert.ToInt32(cmd.ExecuteScalar());
return count > 0;
}
}
注意这里用了参数化查询防止SQL注入,密码也经过MD5加密。再比如实现数据绑定,可以配合MVVM模式:
csharp复制public ObservableCollection<User> GetUsers()
{
var users = new ObservableCollection<User>();
using (var conn = new MySqlConnection(connStr))
{
string sql = "SELECT id, username, email FROM users";
MySqlCommand cmd = new MySqlCommand(sql, conn);
conn.Open();
using (MySqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
users.Add(new User {
Id = dr.GetInt32("id"),
Username = dr.GetString("username"),
Email = dr.GetString("email")
});
}
}
}
return users;
}
数据库操作最常见的异常就是连接超时,我习惯用重试机制应对:
csharp复制int retryCount = 0;
bool success = false;
while (!success && retryCount < 3)
{
try
{
using (var conn = new MySqlConnection(connStr))
{
conn.Open();
// 执行操作...
success = true;
}
}
catch (MySqlException ex)
{
retryCount++;
if (ex.Number == 1042) // 连接超时错误码
{
Thread.Sleep(1000 * retryCount);
continue;
}
throw;
}
}
调试时建议开启MySQL的查询日志,在my.ini中添加:
ini复制general_log = 1
general_log_file = "mysql_query.log"
这样所有执行的SQL语句都会记录到日志文件,特别适合排查复杂的查询问题。另外记得在app.config中加入调试配置:
xml复制<system.diagnostics>
<sources>
<source name="MySql.Data" switchValue="Verbose">
<listeners>
<add name="MySqlLog"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="MySqlLog" type="System.Diagnostics.TextWriterTraceListener"
initializeData="mysql_trace.log"/>
</sharedListeners>
</system.diagnostics>
处理大量数据时,这几个技巧能显著提升性能:
使用连接池:在连接字符串中加入
code复制Pooling=true;Max Pool Size=100;Connection Lifetime=30
批量插入数据用LOAD DATA INFILE:
csharp复制string sql = "LOAD DATA LOCAL INFILE 'data.csv' INTO TABLE users";
预编译常用语句:
csharp复制var cmd = new MySqlCommand("SELECT * FROM users WHERE id=@id", conn);
cmd.Parameters.Add("@id", MySqlDbType.Int32);
cmd.Prepare();
// 循环执行时只需更新参数值
cmd.Parameters["@id"].Value = userId;
异步操作避免UI卡顿:
csharp复制public async Task<List<User>> GetUsersAsync()
{
using (var conn = new MySqlConnection(connStr))
{
await conn.OpenAsync();
var cmd = new MySqlCommand("SELECT * FROM users", conn);
using (var reader = await cmd.ExecuteReaderAsync())
{
var users = new List<User>();
while (await reader.ReadAsync())
{
// 解析数据...
}
return users;
}
}
}
最后我们整合所有知识点,做个完整的学生信息管理系统。先设计数据库表:
sql复制CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
gender ENUM('男','女'),
birthday DATE,
class_id INT,
INDEX(class_id)
);
CREATE TABLE classes (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL
);
在WPF中实现CRUD操作,比如新增学生:
csharp复制public int AddStudent(Student student)
{
string sql = @"INSERT INTO students
(name, gender, birthday, class_id)
VALUES (@name, @gender, @birthday, @classId);
SELECT LAST_INSERT_ID();";
using (var conn = new MySqlConnection(connStr))
{
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@name", student.Name);
cmd.Parameters.AddWithValue("@gender", student.Gender);
cmd.Parameters.AddWithValue("@birthday", student.Birthday);
cmd.Parameters.AddWithValue("@classId", student.ClassId);
conn.Open();
return Convert.ToInt32(cmd.ExecuteScalar());
}
}
配合DataGrid实现数据绑定:
xml复制<DataGrid x:Name="StudentGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="姓名" Binding="{Binding Name}"/>
<DataGridTextColumn Header="性别" Binding="{Binding Gender}"/>
<DataGridTextColumn Header="生日" Binding="{Binding Birthday,StringFormat=yyyy-MM-dd}"/>
</DataGrid.Columns>
</DataGrid>
后台刷新数据:
csharp复制private void RefreshStudentList()
{
var students = new List<Student>();
string sql = @"SELECT s.*, c.name as class_name
FROM students s LEFT JOIN classes c ON s.class_id=c.id";
using (var conn = new MySqlConnection(connStr))
{
var cmd = new MySqlCommand(sql, conn);
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
students.Add(new Student {
Id = reader.GetInt32("id"),
Name = reader.GetString("name"),
Gender = reader.GetString("gender"),
Birthday = reader.GetDateTime("birthday"),
ClassName = reader.IsDBNull("class_name") ? null : reader.GetString("class_name")
});
}
}
}
StudentGrid.ItemsSource = students;
}