PHP脚本执行SQL语句无报错但数据库未更新
你遇到的这个问题确实挺闹心的——明明PHP脚本执行没报错,还输出了成功提示,数据库却纹丝不动,直接在SSMS跑SQL又完全正常,之前还好好的突然就不行了。咱们一步步来排查可能的原因:
先检查事务提交的问题
有些ODBC驱动默认是关闭自动提交的,哪怕你用odbc_exec执行了写操作,也需要手动提交才能生效。你可以试试在执行SQL之后加上这行代码:odbc_commit(CONNECTION);也可以先打印下当前连接的自动提交状态,确认是不是这个问题:
echo odbc_autocommit(CONNECTION); // 返回0就是自动提交关闭,1是开启排查SQL拼接的隐形问题
你贴的是固定的SQL示例,但实际代码里$SQL_ORDERS_INSERT应该是动态生成的吧?很可能动态拼接的时候出了问题——比如某个变量带了不可见字符(换行、制表符)、引号不匹配,或者空格多了少了,导致生成的SQL和你在SSMS里跑的不一样。
建议你把实际执行的SQL打印出来看看:echo $SQL_ORDERS_INSERT;然后把这段输出的SQL复制到SSMS里跑一遍,看看是不是真的能更新数据——很多时候问题就出在这,你以为的SQL和实际执行的完全不是一回事。
检查ODBC连接和代码的小bug
你代码里有一行odbc_free_result($ORDER_ADD);,但你执行SQL的时候并没有把odbc_exec的返回值赋值给$ORDER_ADD啊!这行代码其实是无效的,甚至可能抛出错误,只不过你的try-catch没捕获到?建议先把这行注释掉试试,毕竟你执行的是INSERT/UPDATE操作,根本不需要释放结果集。
另外,也可以检查下ODBC驱动是不是更新了,或者连接字符串的参数有没有变化——比如之前用的是旧版驱动,现在换成了新版,有些默认参数变了也会导致这种奇怪的问题。优化SQL逻辑,避免竞态问题
你现在的SQL是先判断不存在就插入,存在就更新,这种写法在高并发场景下可能会出现竞态问题(比如两次判断之间有其他进程插入了数据),而且也不够原子化。建议换成MERGE语句,把整个操作变成一个原子性的操作:MERGE INTO dbo.ORDERS AS target USING (SELECT 'ELD24-11-50' AS ORDER_NUMBER) AS source ON target.ORDER_NUMBER = source.ORDER_NUMBER WHEN NOT MATCHED THEN INSERT (ORDER_NUMBER, TRANSACTION_TYPE, TRANSPORTER_CODE, SUPPLIER_CODE, SOURCE_CODE, CLIENT_CODE, DESTINATION_CODE, ORDER_STATUS, ORDER_DATE, PRODUCT_CODE, TOTAL_WEIGHT, REMAINING, COMMENT_DESCRIPTION_1, COMMENT_1, COMMENT_DESCRIPTION_2, COMMENT_2, COMMENT_DESCRIPTION_3, COMMENT_3, REMAINING_TRUCKS, EMAIL_SENT, ORDER_SUCCESSOR, BARCODE_RECEIVING, SEAL_QUANTITY, SLIP_FIRST_WEIGH, TRUCKS_PER_DAY, NWP_SYNC) VALUES ('ELD24-11-50', 'DISPATCHING', 'VRC', 'ELD', 'CHROME ', 'CHR', 'WB', 'ACTIVE', '2024-11-01 13:43', 'CHR001', '3100000', '-56400', '', '', '', '', '', '', '-1', '0', '', '0', '2', 'N/A', '999', '0') WHEN MATCHED THEN UPDATE SET TRANSACTION_TYPE = 'DISPATCHING', TRANSPORTER_CODE = 'VRC', SUPPLIER_CODE = 'ELD', SOURCE_CODE = 'CHROME ', CLIENT_CODE = 'CHR', DESTINATION_CODE = 'WB', ORDER_STATUS = 'COMPLETE', ORDER_DATE = '2024-11-01 13:43', PRODUCT_CODE = 'CHR001', TOTAL_WEIGHT = '3100000', REMAINING = '-56400', COMMENT_DESCRIPTION_1 = '', COMMENT_1 = '', COMMENT_DESCRIPTION_2 = '', COMMENT_2 = '', COMMENT_DESCRIPTION_3 = '', COMMENT_3 = '', REMAINING_TRUCKS = '-1', EMAIL_SENT = '0', ORDER_SUCCESSOR = '', BARCODE_RECEIVING = '0', SEAL_QUANTITY = '2', SLIP_FIRST_WEIGH = 'N/A', TRUCKS_PER_DAY = '999', NWP_SYNC = '1';最后确认权限和环境
虽然之前能正常用,但还是要确认下PHP脚本用的ODBC账号和你SSMS用的账号权限是否一致——会不会账号被改了权限?另外,一定要确认PHP连接的数据库和你SSMS操作的是同一个库,别搞成测试库和生产库搞混了!
备注:内容来源于stack exchange,提问作者Madeline Kallis

